Chapter 14 . JDK8新特性
14.1 Lambda 表達(dá)式
Lambda 是一個(gè)匿名函數(shù),我們可以把 Lambda
表達(dá)式理解為是一段可以傳遞的代碼(將代碼
像數(shù)據(jù)一樣進(jìn)行傳遞)??梢詫懗龈啙?、更
靈活的代碼。作為一種更緊湊的代碼風(fēng)格,使
Java的語言表達(dá)能力得到了提升
?


Lambda 表達(dá)式語法
Lambda 表達(dá)式在Java 語言中引入了一個(gè)新的語法元
素和操作符。這個(gè)操作符為 “->” , 該操作符被稱
為 Lambda 操作符或剪頭操作符。它將 Lambda 分為
兩個(gè)部分:
左側(cè): 指定了 Lambda 表達(dá)式需要的所有參數(shù)
右側(cè): 指定了 Lambda 體,即 Lambda 表達(dá)式要執(zhí)行
的功能


類型推斷
上述 Lambda 表達(dá)式中的參數(shù)類型都是由編譯器推斷得出的。
Lambda 表達(dá)式中無需指定類型,程序依然可以編譯,這是因?yàn)?javac 根據(jù)程序的上下文,在后臺
推斷出了參數(shù)的類型。Lambda 表達(dá)式的類型依賴于上
下文環(huán)境,是由編譯器推斷出來的。這就是所謂的
“類型推斷”
14.2 函數(shù)式接口
只包含一個(gè)抽象方法的接口,稱為函數(shù)式接口。
你可以通過 Lambda 表達(dá)式來創(chuàng)建該接口的對象。(若 Lambda
表達(dá)式拋出一個(gè)受檢異常,那么該異常需要在目標(biāo)接口的抽象方
法上進(jìn)行聲明)。-
我們可以在任意函數(shù)式接口上使用 @FunctionalInterface 注解,
這樣做可以檢查它是否是一個(gè)函數(shù)式接口,同時(shí) javadoc 也會包
含一條聲明,說明這個(gè)接口是一個(gè)函數(shù)式接口。image



14.3 方法引用與構(gòu)造器引用
當(dāng)要傳遞給Lambda體的操作,已經(jīng)有實(shí)現(xiàn)的方法了,可以使用方法引用!
(實(shí)現(xiàn)抽象方法的參數(shù)列表,必須與方法引用方法的參數(shù)列表保持一致! )
方法引用:使用操作符 “::” 將方法名和對象或類的名字分隔開來。
如下三種主要使用情況:
對象::實(shí)例方法
類::靜態(tài)方法
類::實(shí)例方法




14.4 Stream API
Java8中有兩大最為重要的改變。第一個(gè)是 Lambda 表達(dá)式;另外一
個(gè)則是 Stream API(java.util.stream.*)。
Stream 是 Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對
集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。
使用Stream API 對集合數(shù)據(jù)進(jìn)行操作,就類似于使用 SQL 執(zhí)行的數(shù)
據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作。簡而言之,
Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
流(Stream) 到底是什么呢?
是數(shù)據(jù)渠道,用于操作數(shù)據(jù)源(集合、數(shù)組等)所生成的元素序列。
“集合講的是數(shù)據(jù),流講的是計(jì)算! ”
注意:
①Stream 自己不會存儲元素。
②Stream 不會改變源對象。相反,他們會返回一個(gè)持有結(jié)果的新Stream。
③Stream 操作是延遲執(zhí)行的。這意味著他們會等到需要結(jié)果的時(shí)候才執(zhí)行。
Stream 的操作三個(gè)步驟
- 創(chuàng)建 Stream
一個(gè)數(shù)據(jù)源(如: 集合、數(shù)組), 獲取一個(gè)流
- 中間操作
一個(gè)中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理
- 終止操作(終端操作)
一個(gè)終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果
創(chuàng)建 Stream
Java8 中的 Collection 接口被擴(kuò)展,提供了
兩個(gè)獲取流的方法:
default Stream<E> stream() : 返回一個(gè)順序流
default Stream<E> parallelStream() : 返回一個(gè)并行流
由數(shù)組創(chuàng)建流
Java8 中的 Arrays 的靜態(tài)方法 stream() 可以獲取數(shù)組流:
static <T> Stream<T> stream(T[] array): 返回一個(gè)流
重載形式,能夠處理對應(yīng)基本類型的數(shù)組:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
由值創(chuàng)建流
可以使用靜態(tài)方法 Stream.of(), 通過顯示值創(chuàng)建一個(gè)流。它可以接收任意數(shù)量的參數(shù)。
public static<T> Stream<T> of(T... values) : 返回一個(gè)流
由函數(shù)創(chuàng)建流:創(chuàng)建無限流
可以使用靜態(tài)方法 Stream.iterate() 和
Stream.generate(), 創(chuàng)建無限流。
- 迭代
public static<T> Stream<T> iterate(final T seed, final
UnaryOperator<T> f)
- 生成
public static<T> Stream<T> generate(Supplier<T> s) :
14.5 Stream 的中間操作
多個(gè)中間操作可以連接起來形成一個(gè)流水線,除非流水
線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何的處理!
而在終止操作時(shí)一次性全部處理,稱為“惰性求值” 。



14.6 Stream 的終止操作
終端操作會從流的流水線生成結(jié)果。
其結(jié)果可以是任何不是流的
值,例如: List、 Integer,甚至是 void 。





14.7 并行流與串行流
并行流就是把一個(gè)內(nèi)容分成多個(gè)數(shù)據(jù)塊,并用不同的線程分
別處理每個(gè)數(shù)據(jù)塊的流。
Java 8 中將并行進(jìn)行了優(yōu)化,我們可以很容易的對數(shù)據(jù)進(jìn)行并
行操作。 Stream API 可以聲明性地通過 parallel() 與
sequential() 在并行流與順序流之間進(jìn)行切換。
14.8 了解 Fork/Join 框架
Fork/Join 框架: 就是在必要的情況下,將一個(gè)大任務(wù),進(jìn)行拆分(fork)成若干個(gè)
小任務(wù)(拆到不可再拆時(shí)),再將一個(gè)個(gè)的小任務(wù)運(yùn)算的結(jié)果進(jìn)行 join 匯總.

Fork/Join 框架與傳統(tǒng)線程池的區(qū)別
采用 “工作竊取”模式(work-stealing): 當(dāng)執(zhí)行新的任務(wù)時(shí)它可以將其拆分分成更小的任務(wù)執(zhí)行,并將小任務(wù)加到線 程隊(duì)列中,然后再從一個(gè)隨機(jī)線程的隊(duì)列中偷一個(gè)并把它放在自己的隊(duì)列中。
相對于一般的線程池實(shí)現(xiàn),fork/join框架的優(yōu)勢體現(xiàn)在對其中包含的任務(wù)的 處理方式上.在一般的線程池中,如果一個(gè)線程正在執(zhí)行的任務(wù)由于某些原因 無法繼續(xù)運(yùn)行,那么該線程會處于等待狀態(tài).
而在fork/join框架實(shí)現(xiàn)中,如果 某個(gè)子問題由于等待另外一個(gè)子問題的完成而無法繼續(xù)運(yùn)行.那么處理該子 問題的線程會主動(dòng)尋找其他尚未運(yùn)行的子問題來執(zhí)行.這種方式減少了線程 的等待時(shí)間,提高了性能.
14.9 新時(shí)間日期 API
使用 LocalDate、 LocalTime、 LocalDateTime
LocalDate、 LocalTime、 LocalDateTime 類的實(shí)
例是不可變的對象,分別表示使用 ISO-8601日
歷系統(tǒng)的日期、時(shí)間、日期和時(shí)間。它們提供
了簡單的日期或時(shí)間,并不包含當(dāng)前的時(shí)間信
息。也不包含與時(shí)區(qū)相關(guān)的信息。
注: ISO-8601日歷系統(tǒng)是國際標(biāo)準(zhǔn)化組織制定的現(xiàn)代公民的日期和時(shí)間的表示法

Instant 時(shí)間戳
用于“時(shí)間戳”的運(yùn)算。它是以Unix元年(傳統(tǒng)
的設(shè)定為UTC時(shí)區(qū)1970年1月1日午夜時(shí)分)開始
所經(jīng)歷的描述進(jìn)行運(yùn)算
Duration 和 Period
Duration:用于計(jì)算兩個(gè)“時(shí)間”間隔
Period:用于計(jì)算兩個(gè)“日期”間隔
日期的操縱
TemporalAdjuster : 時(shí)間校正器。有時(shí)我們可能需要獲
取例如:將日期調(diào)整到“下個(gè)周日”等操作。
l TemporalAdjusters : 該類通過靜態(tài)方法提供了大量的常
用 TemporalAdjuster 的實(shí)現(xiàn)。
例如獲取下個(gè)周日:

解析與格式化
java.time.format.DateTimeFormatter 類:該類提供了三種
格式化方法:
預(yù)定義的標(biāo)準(zhǔn)格式
語言環(huán)境相關(guān)的格式
自定義的格式
時(shí)區(qū)的處理
Java8 中加入了對時(shí)區(qū)的支持,帶時(shí)區(qū)的時(shí)間為分別為:
ZonedDate、 ZonedTime、 ZonedDateTime
其中每個(gè)時(shí)區(qū)都對應(yīng)著 ID,地區(qū)ID都為 “{區(qū)域}/{城市}”的格式
例如 : Asia/Shanghai 等
ZoneId:該類中包含了所有的時(shí)區(qū)信息
getAvailableZoneIds() : 可以獲取所有時(shí)區(qū)時(shí)區(qū)信息
of(id) : 用指定的時(shí)區(qū)信息獲取 ZoneId 對象
與傳統(tǒng)日期處理的轉(zhuǎn)換

14.10 接口中的默認(rèn)方法與靜態(tài)方法
Java 8中允許接口中包含具有具體實(shí)現(xiàn)的方法,該方法稱為
“默認(rèn)方法”,默認(rèn)方法使用 default 關(guān)鍵字修飾。

接口默認(rèn)方法的” 類優(yōu)先” 原則
若一個(gè)接口中定義了一個(gè)默認(rèn)方法,而另外一個(gè)父類或接口中
又定義了一個(gè)同名的方法時(shí)
選擇父類中的方法。如果一個(gè)父類提供了具體的實(shí)現(xiàn),那么
接口中具有相同名稱和參數(shù)的默認(rèn)方法會被忽略。接口沖突。如果一個(gè)父接口提供一個(gè)默認(rèn)方法,而另一個(gè)接
口也提供了一個(gè)具有相同名稱和參數(shù)列表的方法(不管方法
是否是默認(rèn)方法), 那么必須覆蓋該方法來解決沖突

接口中的靜態(tài)方法
Java8 中,接口中允許添加靜態(tài)方法。

14.11 其他新特性
Optional 類
Optional<T> 類(java.util.Optional) 是一個(gè)容器類,代表一個(gè)值存在或不存在, 原來用 null 表示一個(gè)值不存在,現(xiàn)在 Optional 可以更好的表達(dá)這個(gè)概念。并且 可以避免空指針異常。
常用方法:
Optional.of(T t) : 創(chuàng)建一個(gè) Optional 實(shí)例
Optional.empty() : 創(chuàng)建一個(gè)空的 Optional 實(shí)例
Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建 Optional 實(shí)例,否則創(chuàng)建空實(shí)例
isPresent() : 判斷是否包含值
orElse(T t) : 如果調(diào)用對象包含值,返回該值,否則返回t
orElseGet(Supplier s) :如果調(diào)用對象包含值,返回該值,否則返回 s 獲取的值
map(Function f): 如果有值對其處理,并返回處理后的Optional,否則返回 Optional.empty()
flatMap(Function mapper):與 map 類似,要求返回值必須是Optional
重復(fù)注解與類型注解
Java 8對注解處理提供了兩點(diǎn)改進(jìn):可重復(fù)的注解及可用于類
型的注解。

