摘要:新特性總覽標(biāo)簽本文主要介紹的新特性,包括表達(dá)式方法引用流默認(rèn)方法組合式異步編程新的時(shí)間,等等各個(gè)方面。還有對(duì)應(yīng)的和類型的函數(shù)連接字符串廣義的歸約匯總起始值,映射方法,二元結(jié)合二元結(jié)合。使用并行流時(shí)要注意避免共享可變狀態(tài)。
Java8新特性總覽
標(biāo)簽: java
[TOC]
本文主要介紹 Java 8 的新特性,包括 Lambda 表達(dá)式、方法引用、流(Stream API)、默認(rèn)方法、Optional、組合式異步編程、新的時(shí)間 API,等等各個(gè)方面。
寫在前面基礎(chǔ)知識(shí)本文是《Java 8 in Action》的讀書筆記,主要提煉了概念性的知識(shí)/觀點(diǎn)性的結(jié)論,對(duì)推導(dǎo)和闡釋沒有摘錄
文中涉及到的源碼請(qǐng)參考我在 GitHub 上的項(xiàng)目 java-learning (地址為 https://github.com/brianway/java-learning)的 Java 8 模塊部分,比書中參考源碼分類更清晰
Java 8 的主要想法:
stream API
向方法傳遞代碼的技巧(方法引用、Lambda)
接口中的默認(rèn)方法
三個(gè)編程概念:
流處理(好處:更高抽象,免費(fèi)并行)
行為參數(shù)化(通過 API 來傳遞代碼)
并行與共享的可變數(shù)據(jù)
函數(shù)式編程范式的基石:
沒有共享的可變數(shù)據(jù)
將方法和函數(shù)即代碼傳遞給其它方法的能力
Java 8 使用 Stream API 解決了兩個(gè)問題:
集合處理時(shí)的套路和晦澀
難以利用多核
Collection 主要是為了存儲(chǔ)和訪問數(shù)據(jù),而 Stream 則主要用于描述對(duì)數(shù)據(jù)的計(jì)算。
通過行為參數(shù)化來傳遞代碼行為參數(shù)化:類似于策略設(shè)計(jì)模式
類 -> 匿名類 -> Lambda 表達(dá)式,代碼越來越簡(jiǎn)潔
Lambda 表達(dá)式Lambda 表達(dá)式:簡(jiǎn)潔地表示可傳遞的匿名函數(shù)的一種方式
重點(diǎn)留意這四個(gè)關(guān)鍵詞:匿名、函數(shù)、傳遞、簡(jiǎn)潔
三個(gè)部分:
參數(shù)列表
箭頭
Lambda 主體
Lambda 基本語法,下面兩者之一:
(parameters) -> expression
(parameters) -> { statements; }
函數(shù)式接口:只定義一個(gè)抽象方法的接口。函數(shù)式接口的抽象方法的簽名稱為 函數(shù)描述符
Lambda 表達(dá)式允許你以內(nèi)聯(lián)的形式為函數(shù)式接口的抽象方法提供實(shí)現(xiàn),并把整個(gè)表達(dá)式作為函數(shù)式接口(一個(gè)具體實(shí)現(xiàn))的實(shí)例。
常用函數(shù)式接口有:Predicate, Consumer, Function, Supplier 等等。
Lambda 的類型是從使用 Lambda 的上下文推斷出來的。上下文中 Lambda 表達(dá)式需要的類型稱為目標(biāo)類型。
方法引用方法引用主要有三類:
(1) 指向靜態(tài)方法的方法引用
Lambda: (args) -> ClassName.staticMethod(args)
方法引用:ClassName::staticMethod
(2) 指向任意類型實(shí)例方法的方法引用
Lambda: (arg0, rest) -> arg0.instanceMethod(rest)
方法引用:ClassName::instanceMethod(arg0 是 ClassName 類型的)
(3) 指向現(xiàn)有對(duì)象的實(shí)例方法的方法引用
Lambda: (args) -> expr.instanceMethod(args)
方法引用:expr::intanceMethod
方法引用就是替代那些轉(zhuǎn)發(fā)參數(shù)的 Lambda 表達(dá)式的語法糖
流(Stream API)引入的原因:
聲明性方式處理數(shù)據(jù)集合
透明地并行處理,提高性能
流 的定義:從支持?jǐn)?shù)據(jù)處理操作的源生成的元素序列
兩個(gè)重要特點(diǎn):
流水線
內(nèi)部迭代
流與集合:
集合與流的差異就在于什么時(shí)候進(jìn)行計(jì)算
集合是內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),包含數(shù)據(jù)結(jié)構(gòu)中目前所有的值
流的元素則是按需計(jì)算/生成
另一個(gè)關(guān)鍵區(qū)別在于遍歷數(shù)據(jù)的方式
集合使用 Collection 接口,需要用戶去做迭代,稱為外部迭代
流的 Streams 庫使用內(nèi)部迭代
流操作主要分為兩大類:
中間操作:可以連接起來的流操作
終端操作:關(guān)閉流的操作,觸發(fā)流水線執(zhí)行并關(guān)閉它
流的使用:
一個(gè)數(shù)據(jù)源(如集合)來執(zhí)行一個(gè)查詢;
一個(gè)中間操作鏈,形成一條流的流水線;
一個(gè)終端操作,執(zhí)行流水線,并能生成結(jié)果。
流的流水線背后的理念類似于構(gòu)建器模式。常見的中間操作有 filter,map,limit,sorted,distinct;常見的終端操作有 forEach,count,collect。
使用流
篩選
謂詞篩選:filter
篩選互異的元素:distinct
忽略頭幾個(gè)元素:limit
截短至指定長(zhǎng)度:skip
映射
對(duì)流中每個(gè)元素應(yīng)用函數(shù):map
流的扁平化:flatMap
查找和匹配
檢查謂詞是否至少匹配一個(gè)元素:anyMatch
檢查謂詞是否匹配所有元素:allMatch/noneMatch
查找元素:findAny
查找第一個(gè)元素:findFirst
歸約(折疊):reduce(初值,結(jié)合操作)
元素求和
最大值和最小值
anyMatch,allMatch,noneMatch 都用到了短路;distinct,sorted是有狀態(tài)且無界的,skip,limit,reduce是有狀態(tài)且有界的。
原始類型流特化:IntStream,DoubleStream,LongStream,避免暗含的裝箱成本。
映射到數(shù)值流:mapToInt,mapToDouble,mapToLong
轉(zhuǎn)換回流對(duì)象:boxed
默認(rèn)值:OptionalInt,OptionalDouble,OptionalLong
數(shù)值范圍:
range:[起始值,結(jié)束值)
rangeClosed:[起始值,結(jié)束值]
構(gòu)建流由值創(chuàng)建流:Stream.of,Stream.empty
由數(shù)組創(chuàng)建流:Arrays.stream(數(shù)組變量)
由文件生成流:Files.lines
由函數(shù)生成流:創(chuàng)建無限流,
迭代: Stream.iterate
生成:Stream.generate
用流收集數(shù)據(jù)對(duì)流調(diào)用 collect 方法將對(duì)流中的元素觸發(fā)歸約操作(由 Collector 來參數(shù)化)。
Collectors 實(shí)用類提供了許多靜態(tài)工廠方法,用來創(chuàng)建常見收集器的實(shí)例,主要提供三大功能:
將流元素歸約和匯總為一個(gè)值
元素分組
元素分區(qū)
歸約和匯總(Collectors 類中的工廠方法):
統(tǒng)計(jì)個(gè)數(shù):Collectors.counting
查找流中最大值和最小值:Collectors.maxBy,Collectors.minBy
匯總:Collectors.summingInt,Collectors.averagingInt,summarizingInt/IntSummaryStatistics。還有對(duì)應(yīng)的 long 和 double 類型的函數(shù)
連接字符串:joining
廣義的歸約匯總:Collectors.reducing(起始值,映射方法,二元結(jié)合)/Collectors.reducing(二元結(jié)合)。Collectors.reducing 工廠方法是所有上述特殊情況的一般化。
collect vs. reduce,兩者都是 Stream 接口的方法,區(qū)別在于:
語意問題
reduce 方法旨在把兩個(gè)值結(jié)合起來生成一個(gè)新值,是不可變的歸約;
collect 方法設(shè)計(jì)就是要改變?nèi)萜鳎瑥亩鄯e要輸出的結(jié)果
實(shí)際問題
以錯(cuò)誤的語義使用 reduce 會(huì)導(dǎo)致歸約過程不能并行工作
分組和分區(qū)
分組:Collectors.groupingBy
多級(jí)分組
按子數(shù)組收集數(shù)據(jù): maxBy
把收集器的結(jié)果轉(zhuǎn)換為另一種結(jié)果 collectingAndThen
與 groupingBy 聯(lián)合使用的其他收集器例子:summingInt,mapping
分區(qū):是分組的特殊情況,由一個(gè)謂詞作為分類函數(shù)(分區(qū)函數(shù))
收集器接口:Collector,部分源碼如下:
public interface Collector{ Supplier supplier(); BiConsumer accumulator(); Function finisher(); BinaryOperator combiner(); Set characteristics(); }
其中 T、A、R 分別是流中元素的類型、用于累積部分結(jié)果的對(duì)象類型,以及 collect 操作最終結(jié)果的類型。
建立新的結(jié)果容器:supplier 方法
將元素添加到結(jié)果容器:accumulator 方法,累加器是原位更新
對(duì)結(jié)果容器應(yīng)用最終轉(zhuǎn)換: finisher 方法
合并兩個(gè)結(jié)果容器:combiner 方法
定義收集器的行為: characteristics 方法,Characteristics 包含 UNORDERED,CONCURRENT,IDENTITY_FINISH
前三個(gè)方法已經(jīng)足以對(duì)流進(jìn)行順序歸約,實(shí)踐中實(shí)現(xiàn)會(huì)復(fù)雜點(diǎn),一是因?yàn)榱鞯难舆t性質(zhì),二是理論上可能要進(jìn)行并行歸約。
Collectors.toList 的源碼實(shí)現(xiàn):
public static并行流Collector > toList() { return new CollectorImpl<>( (Supplier >) ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID); } // static final Set
CH_ID = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
并行流就是一個(gè)把內(nèi)容分成多個(gè)數(shù)據(jù)塊,并用不同的線程分別處理每個(gè)數(shù)據(jù)塊的流。
關(guān)于并行流的幾點(diǎn)說明:
選擇適當(dāng)?shù)臄?shù)據(jù)結(jié)構(gòu)往往比并行化算法更重要,比如避免拆箱裝箱的開銷,使用便于拆分的方法而非 iterate。
同時(shí),要保證在內(nèi)核中并行執(zhí)行工作的時(shí)間比在內(nèi)核之間傳輸數(shù)據(jù)的時(shí)間長(zhǎng)。
使用并行流時(shí)要注意避免共享可變狀態(tài)。
并行流背后使用的基礎(chǔ)架構(gòu)是 Java 7 中引入的分支/合并框架。
分支/合并框架
分支/合并框架的目的是以遞歸的方式將可以并行的任務(wù)拆分成更小的任務(wù),然后將每個(gè)子任務(wù)的結(jié)果合并起來生成整體結(jié)果。
RecursiveTast
將任務(wù)拆分成子任務(wù)的邏輯
無法/不方便再拆分時(shí),生成單個(gè)子任務(wù)結(jié)果的邏輯
對(duì)任務(wù)調(diào)用 fork 方法可以把它排進(jìn) ForkJoinPool,同時(shí)對(duì)左邊和右邊的子任務(wù)調(diào)用 fork 的效率要比直接對(duì)其中一個(gè)調(diào)用 compute 低,因?yàn)榭梢云渲幸粋€(gè)子任務(wù)可以重用同一線程,減少開銷
工作竊取:用于池中的工作線程之間重新分配和平衡任務(wù)。
Spliterator 代表“可分迭代器”,用于遍歷數(shù)據(jù)源中的元素。可以延遲綁定。
高效 Java 8 編程 重構(gòu)、測(cè)試、調(diào)試
改善代碼的可讀性
用 Lambda 表達(dá)式取代匿名類
用方法引用重構(gòu) Lambda 表達(dá)式
用 Stream API 重構(gòu)命令式的數(shù)據(jù)處理
增加代碼的靈活性
采用函數(shù)接口
有條件的延遲執(zhí)行
環(huán)繞執(zhí)行
使用 Lambda 重構(gòu)面向?qū)ο蟮脑O(shè)計(jì)模式:
策略模式
一個(gè)代表某個(gè)算法的接口
一個(gè)或多個(gè)該接口的具體實(shí)現(xiàn),它們代表的算法的多種實(shí)現(xiàn)
一個(gè)或多個(gè)使用策略對(duì)象的客戶
模版方法
傳統(tǒng):繼承抽象類,實(shí)現(xiàn)抽象方法
Lambda:添加一個(gè)參數(shù),直接插入不同的行為,無需繼承
觀察者模式
執(zhí)行邏輯較簡(jiǎn)單時(shí),可以用 Lambda 表達(dá)式代替類
責(zé)任鏈模式
工廠模式
傳統(tǒng):switch case 或者 反射
Lambda:創(chuàng)建一個(gè) Map,將名稱映射到對(duì)應(yīng)的構(gòu)造函數(shù)
調(diào)試的方法:
查看棧跟蹤:無論 Lambda 表達(dá)式還是方法引用,都無法顯示方法名,較難調(diào)試
輸出日志:peek 方法,設(shè)計(jì)初衷就是在流的每個(gè)元素恢復(fù)運(yùn)行之前,插入執(zhí)行一個(gè)動(dòng)作
默認(rèn)方法Java 8 中的接口現(xiàn)在支持在聲明方法的同時(shí)提供實(shí)現(xiàn),通過以下兩種方式可以完成:
Java 8 允許在接口內(nèi)聲明 靜態(tài)方法
Java 8 引入了一個(gè)新功能:默認(rèn)方法
默認(rèn)方法的引入就是為了以兼容的方式解決像 Java API 這樣的類庫的演進(jìn)問題的。它讓類可以自動(dòng)地繼承接口的一個(gè)默認(rèn)實(shí)現(xiàn)。
向接口添加新方法是 二進(jìn)制兼容 的,即如果不重新編譯該類,即使不實(shí)現(xiàn)新的方法,現(xiàn)有類的實(shí)現(xiàn)依舊可以運(yùn)行。默認(rèn)方法 是一種以 源碼兼容 方式向接口內(nèi)添加實(shí)現(xiàn)的方法。
抽象類和抽象接口的區(qū)別:
一個(gè)類只能繼承一個(gè)抽象類,但一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
一個(gè)抽象類可以通過實(shí)例變量保存一個(gè)通用狀態(tài),而接口不能有實(shí)例變量
默認(rèn)方法的兩種用例:
可選方法:提供默認(rèn)實(shí)現(xiàn),減少空方法等無效的模版代碼
行為的多繼承
類型的多繼承
利用正交方法的精簡(jiǎn)接口
組合接口
如果一個(gè)類使用相同的函數(shù)簽名從多個(gè)地方繼承了方法,解決沖突的三條規(guī)則:
類中的方法優(yōu)先級(jí)最高
若 1 無法判斷,那么子接口的優(yōu)先級(jí)更高,即優(yōu)先選擇擁有最具體實(shí)現(xiàn)的默認(rèn)方法的接口
若 2 還無法判斷,那么繼承了多個(gè)接口的類必須通過顯示覆蓋和調(diào)用期望的方法,顯示地選擇使用哪一個(gè)默認(rèn)方法的實(shí)現(xiàn)。
Optional 取代 nullnull 的問題:
錯(cuò)誤之源:NullPointerException 問題
代碼膨脹:各種 null 檢查
自身無意義
破壞了 Java 的哲學(xué): null 指針
在 Java 類型系統(tǒng)上開了個(gè)口子:null 不屬于任何類型
java.util.Optional
創(chuàng)建 Optional 對(duì)象,三個(gè)靜態(tài)工廠方法:
Optional.empty:創(chuàng)建空的 Optional 對(duì)象
Optional.of:依據(jù)非空值創(chuàng)建 Optional 對(duì)象,若傳空值會(huì)拋 NPE
Optianal.ofNullable:創(chuàng)建 Optional 對(duì)象,允許傳空值
使用 map 從 Optional 對(duì)象提取和轉(zhuǎn)換值,Optional 的 map 方法:
若 Optional 包含值,將該值作為參數(shù)傳遞給 map,對(duì)該值進(jìn)行轉(zhuǎn)換后包裝成 Optional
若 Optional 為空,什么也不做,即返回 Optional.empty
使用 flatMap 鏈接 Optional 對(duì)象:
由于 Optional 的 map 方法會(huì)將轉(zhuǎn)換結(jié)果生成 Optional,對(duì)于返回值已經(jīng)為 Optional 的,就會(huì)出現(xiàn) Optional
簡(jiǎn)單來說,返回值是 T 的,就用 map 方法;返回值是 Optional
參數(shù)為 null 時(shí),會(huì)由 Objects.requireNonNull 拋出 NPE;參數(shù)為空的 Optional 對(duì)象時(shí),返回 Optional.empty
參數(shù)非 null/空的 Optional 對(duì)象時(shí),map 返回 Optional;flatMap 返回對(duì)象本身
原因可以參考這兩個(gè)方法的源碼:
public Optional map(Function super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } } public Optional flatMap(Function super T, Optional> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }
另外,Optional 類設(shè)計(jì)的初衷僅僅是要支持能返回 Optional 對(duì)象的方法。設(shè)計(jì)時(shí)并未考慮將其作為類的字段,所以并未實(shí)現(xiàn) Serializable 接口。
默認(rèn)行為及解引用 Optional 對(duì)象:
get(): 返回封裝的變量值,或者拋出 NoSuchElementException
orElse(T other): 提供默認(rèn)值
orElseGet(Supplier extends T> other): orElse 方法的延遲調(diào)用版
orElseThrow(Supplier<> extends X> exceptionSupplier): 類似 get,但可以定制希望拋出的異常類型
ifPresent(Consumer super T>): 變量存在時(shí)可以執(zhí)行一個(gè)方法
CompletableFuture:組合式異步編程Future 接口有一定的局限性。CompletableFuture 和 Future 的關(guān)系就跟 Stream 和 Collection 的關(guān)系一樣。
同步 API 與 異步 API
同步 API:調(diào)用方需要等待被調(diào)用方結(jié)束運(yùn)行,即使兩者是在不同的線程中運(yùn)行
異步 API:直接返回,被調(diào)用方完成之前是將任務(wù)交給另一個(gè)線程去做,該線程和調(diào)用方是異步的,返回方式有如下兩種:
要么通過回調(diào)函數(shù)
要么由調(diào)用方再執(zhí)行一個(gè)“等待,直到計(jì)算完成”的方法調(diào)用
使用工廠方法 supplyAsync 創(chuàng)建 CompletableFuture 比較方便,該方法會(huì)拋出 CompletableFuture 內(nèi)發(fā)生問題的異常。
代碼的阻塞問題的解決方案及如何選擇:
使用并行流對(duì)請(qǐng)求進(jìn)行并行操作:適用于計(jì)算密集型的操作,且沒有 I/O ,此時(shí)推薦使用 Stream 接口
使用 CompletableFuture 發(fā)起異步請(qǐng)求(可以使用定制的執(zhí)行器):若涉及等待 I/O 的操作,使用 CompletableFuture 靈活性更好
注意,CompletableFuture 類中的 join 方法和 Future 接口中的 get 有相同的含義,join 不拋出檢測(cè)異常。另外,需要使用兩個(gè)不同的 Stream 流水線而不是同一個(gè),來避免 Stream的延遲特性引起順序執(zhí)行
構(gòu)造同步和異步操作:
thenApply 方法不會(huì)阻塞代碼的執(zhí)行
thenCompose 方法允許你對(duì)兩個(gè)異步操作進(jìn)行流水線,第一個(gè)操作完成時(shí),將其結(jié)果作為參數(shù)傳遞給第二個(gè)操作
thenCombine 方法將兩個(gè)完全不相干的 CompletableFuture 對(duì)象的結(jié)果整合起來
調(diào)用 get 或者 join 方法只會(huì)造成阻塞,響應(yīng) CompletableFuture 的 completion 事件可以實(shí)現(xiàn)等所有數(shù)據(jù)都完備之后再呈現(xiàn)。thenAccept 方法在每個(gè) CompletableFuture 上注冊(cè)一個(gè)操作,該操作會(huì)在 CompletableFuture 完成執(zhí)行后使用它的返回值,即 thenAccept 定義了如何處理 CompletableFuture 返回的結(jié)果,一旦 CompletableFuture 計(jì)算得到結(jié)果,它就返回一個(gè) CompletableFuture
原來的 java.util.Date 類的缺陷:
這個(gè)類無法表示日期,只能以毫秒的精度表示時(shí)間
易用性差:年份起始 1900 年,月份從 0 起始
toString 方法誤導(dǎo)人:其實(shí)并不支持時(shí)區(qū)
相關(guān)類同樣缺陷很多:
java.util.Calender 類月份依舊從 0 起始
同時(shí)存在 java.util.Date 和 java.util.Calender,徒添困惑
有的特性只在某一個(gè)類提供,如 DateFormat 方法
DateFormat 不是線程安全的
java.util.Date 和 java.util.Calender 都是可變的
一些新的 API(java.time 包)
LocalDate: 該類實(shí)例是一個(gè)不可變對(duì)象,只提供簡(jiǎn)單的日期,并不含當(dāng)天的時(shí)間信息,也不附帶任何和時(shí)區(qū)相關(guān)的信息
LocalTime: 時(shí)間(時(shí)、分、秒)
LocalDateTime: 是 LocalDate 和 LocalTime 的合體,不含時(shí)區(qū)信息
Instant: 機(jī)器的日期和時(shí)間則使用 java.time.Instant 類對(duì)時(shí)間建模,以 Unix 元年時(shí)間開始所經(jīng)歷的秒數(shù)進(jìn)行計(jì)算
Temporal: 上面四個(gè)類都實(shí)現(xiàn)了該接口,該接口定義了如何讀取和操縱為時(shí)間建模的對(duì)象的值
Duration: 創(chuàng)建兩個(gè) Temporal 對(duì)象之間的 duration。LocalDateTime 和 Instant 是為不同目的設(shè)計(jì)的,不能混用,且不能傳遞 LocalDate 當(dāng)參數(shù)。
Period: 得到兩個(gè) LocalDate 之間的時(shí)長(zhǎng)
LocalDate,LocalTime,LocalDateTime 三個(gè)類的實(shí)例創(chuàng)建都有三種工廠方法:of,parse,now
Duration,Period 有很多工廠方法:between,of,還有 ofArribute 之類的
以上日期-時(shí)間對(duì)象都是不可修改的,這是為了更好地支持函數(shù)式編程,確保線程安全
操縱時(shí)間:
withArribute 創(chuàng)建一個(gè)對(duì)象的副本,并按照需要修改它的屬性。更一般地,with 方法。但注意,該方法并不是修改原值,而是返回一個(gè)新的實(shí)例。類似的方法還有 plus,minus 等
使用 TemporalAdjuster 接口: 用于定制化處理日期,函數(shù)式接口,只含一個(gè)方法 adjustInto
TemporalAdjusters: 對(duì)應(yīng)的工具類,有很多自帶的工廠方法。(如果想用 Lamda 表達(dá)式定義 TemporalAdjuster 對(duì)象,推薦使用 TemporalAdjusters 類的靜態(tài)工廠方法 ofDateAdjuster)
打印輸出及解析日期-時(shí)間對(duì)象:主要是 java.time.format 包,最重要的類是 DateTimeFormatter 類,所有該類的實(shí)例都是 線程安全 的,所以可以單例格式創(chuàng)建格式器實(shí)例。
處理不同的時(shí)區(qū)和歷法使用 java.time.ZoneId 類,該類無法修改。
// ZoneDateTime 的組成部分 ZonedDateTime = LocalDateTime + ZoneId = (LocalDate + LocalTime) + ZoneId結(jié)語
本文主要對(duì) Java 8 新特性中的 Lambda 表達(dá)式、Stream API、流(Stream API)、默認(rèn)方法、Optional、組合式異步編程、新的時(shí)間 API,等方面進(jìn)行了簡(jiǎn)單的介紹和羅列,至于更泛化的概念,譬如函數(shù)式編程、Java 語言意外的東西沒有介紹。當(dāng)然,很多細(xì)節(jié)和設(shè)計(jì)思想還需要進(jìn)一步閱讀官網(wǎng)文檔/源碼,在實(shí)戰(zhàn)中去體會(huì)和運(yùn)用。
參考資料《Java 8 in Action》(中文版)/(英文版)
Java 8新特性:全新的Stream API
Java 8 中的 Streams API 詳解
另外附上 lucida 的幾篇譯文:
深入理解Java 8 Lambda(語言篇——lambda,方法引用,目標(biāo)類型和默認(rèn)方法)
深入理解Java 8 Lambda(類庫篇——Streams API,Collectors和并行)
深入理解 Java 8 Lambda(原理篇——Java 編譯器如何處理 lambda)暫時(shí)還沒
作者@brianway更多文章:個(gè)人網(wǎng)站 | CSDN | oschina
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/66895.html
摘要:?jiǎn)栴}是這些服務(wù)都是第三方提供的,不能保證它們的響應(yīng)時(shí)間,快的話美團(tuán)點(diǎn)評(píng)分布式生成系統(tǒng)后端掘金背景在復(fù)雜分布式系統(tǒng)中,往往需要對(duì)大量的數(shù)據(jù)和消息進(jìn)行唯一標(biāo)識(shí)。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進(jìn)階-多線程開發(fā)關(guān)鍵技術(shù) - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必將下面這段話置于文章...
摘要:?jiǎn)栴}是這些服務(wù)都是第三方提供的,不能保證它們的響應(yīng)時(shí)間,快的話美團(tuán)點(diǎn)評(píng)分布式生成系統(tǒng)后端掘金背景在復(fù)雜分布式系統(tǒng)中,往往需要對(duì)大量的數(shù)據(jù)和消息進(jìn)行唯一標(biāo)識(shí)。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進(jìn)階-多線程開發(fā)關(guān)鍵技術(shù) - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必將下面這段話置于文章...
摘要:模板解釋器和字節(jié)碼解釋器差不多,不一樣的地方在于直接把對(duì)應(yīng)的指令集轉(zhuǎn)成本地代碼編譯器可以針對(duì)熱點(diǎn)代碼優(yōu)化,執(zhí)行開銷較大,但是能夠針對(duì)性的優(yōu)化,效率最高垃圾收集器負(fù)責(zé)回收不再使用的對(duì)象,釋放和整理內(nèi)存簡(jiǎn)稱。 (原發(fā)于知乎, 定期同步至segmentfault, 原文地址:知乎-JVM入門系列-JVM總覽)Java宣稱Write Once Run Everywhere,這意味著在一個(gè)平臺(tái)上...
閱讀 2588·2021-10-25 09:45
閱讀 1249·2021-10-14 09:43
閱讀 2307·2021-09-22 15:23
閱讀 1532·2021-09-22 14:58
閱讀 1942·2019-08-30 15:54
閱讀 3549·2019-08-30 13:00
閱讀 1363·2019-08-29 18:44
閱讀 1578·2019-08-29 16:59