本書全面介紹了Java 8、9、10版本的新特性,包括Lambda表達(dá)式、方法引用、流、默認(rèn)方法、Optional、CompletableFuture以及新的日期和時間API,是程序員了解Java新特性的經(jīng)典指南。全書共分六個部分:基礎(chǔ)知識、使用流進(jìn)行函數(shù)式數(shù)據(jù)處理、使用流和Lambda進(jìn)行高效編程、無所不在的Java、提升Java的并發(fā)性、函數(shù)式編程以及Java未來的演進(jìn)。
現(xiàn)代Java應(yīng)用充分利用了微服務(wù)、反應(yīng)式架構(gòu)以及流式數(shù)據(jù)等創(chuàng)新設(shè)計,F(xiàn)代Java特性,譬如Lambda、流以及大家期待已久的Java模塊系統(tǒng)讓這些設(shè)計的實現(xiàn)極其便利。是時候更新技能工具箱了,只有這樣,你才能從容應(yīng)對迎面而來的種種挑戰(zhàn)! 本書通過透徹的示例和通俗的語言講解了Java語言這些激動人心的特性,作者注重細(xì)節(jié),努力降低了學(xué)習(xí)難度,節(jié)省你寶貴的時間。依照本書邊學(xué)邊練,你可以很快掌握流應(yīng)用程序接口、Java模塊系統(tǒng)等現(xiàn)代Java新特性,再進(jìn)一步去探尋實現(xiàn)并發(fā)的新方法,了解函數(shù)式編程如何幫你編寫可讀性好又容易維護(hù)的代碼。潛心修煉,你的編程實力必能提高到新的層次。 本書特色: ●對上一版(《Java 8實戰(zhàn)》)做了全新改版 ●Java 8、9、10及后續(xù)版本新特性介紹 ●流數(shù)據(jù)處理以及反應(yīng)式編程 ●Java模塊系統(tǒng)
拉烏爾?C加布里埃爾·烏爾瑪(Raoul-Gabriel Urma),劍橋大學(xué)計算機(jī)科學(xué)博士,軟件工程師,培訓(xùn)師,現(xiàn)任Cambridge Spark公司CEO。在谷歌、eBay、甲骨文和高盛等大公司工作過,并參與過多個創(chuàng)業(yè)項目。活躍在技術(shù)社區(qū),經(jīng)常撰寫技術(shù)文章,多次受邀在國際會議上做技術(shù)講座。 馬里奧·富斯科(Mario Fusco),Red Hat高級軟件工程師,負(fù)責(zé)JBoss規(guī)則引擎Drools的核心開發(fā)。擁有豐富的Java開發(fā)經(jīng)驗,曾領(lǐng)導(dǎo)媒體公司、金融部門等多個行業(yè)的企業(yè)級項目開發(fā)。對函數(shù)式編程和領(lǐng)域特定語言等有濃厚興趣,并創(chuàng)建了開放源碼庫lambdaj。 艾倫·米克羅夫特(Alan Mycroft),劍橋大學(xué)計算機(jī)實驗室計算學(xué)教授,劍橋大學(xué)羅賓遜學(xué)院研究員,歐洲編程語言和系統(tǒng)協(xié)會聯(lián)合創(chuàng)始人,樹莓派基金會聯(lián)合創(chuàng)始人和理事。發(fā)表過大約100篇研究論文,指導(dǎo)過20多篇博士論文。他的研究主要關(guān)注編程語言及其語義、優(yōu)化和實施。他與業(yè)界聯(lián)系緊密,曾于學(xué)術(shù)休假期間在AT&T實驗室和英特爾工作,還創(chuàng)立了Codemist公司,該公司設(shè)計了最初的ARM C編譯器Norcroft。 【譯者介紹】 陸明剛,畢業(yè)于四川大學(xué),目前在Dell EMC中國卓越研發(fā)集團(tuán)任高級主管工程師,曾任趨勢科技中國軟件研發(fā)中心技術(shù)經(jīng)理,在信息科學(xué)和工程領(lǐng)域有十余年的實踐和研究經(jīng)驗,擁有多項中國及美國專利。關(guān)注JVM性能調(diào)優(yōu)和大數(shù)據(jù)及其實踐,喜歡挖掘技術(shù)背后的內(nèi)幕并樂此不疲。 勞佳,上海交通大學(xué)碩士,現(xiàn)任SAP(美國)高級軟件支持顧問。業(yè)余愛好語言、數(shù)學(xué)、設(shè)計,英、法雙語譯者,近年翻譯出版了《咨詢的奧秘》《卓越程序員密碼》《計算進(jìn)化史:改變數(shù)學(xué)的命運(yùn)》等書。
第 一部分 基礎(chǔ)知識
第 1 章 Java 8、9、10以及11的變化 2
1.1 為什么要關(guān)心Java的變化 2
1.2 Java怎么還在變 4
1.2.1 Java在編程語言生態(tài)系統(tǒng)中的位置 5
1.2.2 流處理 6
1.2.3 用行為參數(shù)化把代碼傳遞給方法 7
1.2.4 并行與共享的可變數(shù)據(jù) 8
1.2.5 Java需要演變 9
1.3 Java中的函數(shù) 9
1.3.1 方法和Lambda作為一等值 10
1.3.2 傳遞代碼:一個例子 11
1.3.3 從傳遞方法到Lambda 13
1.4 流 14
1.5 默認(rèn)方法及Java模塊 17
1.6 來自函數(shù)式編程的其他好思想 19
1.7 小結(jié) 20
第 2 章 通過行為參數(shù)化傳遞代碼 22
2.1 應(yīng)對不斷變化的需求 23
2.1.1 初試牛刀:篩選綠蘋果 23
2.1.2 再展身手:把顏色作為參數(shù) 23
2.1.3 第三次嘗試:對你能想到的每個屬性做篩選 24
2.2 行為參數(shù)化 25
2.3 對付啰唆 30
2.3.1 匿名類 30
2.3.2 第五次嘗試:使用匿名類 31
2.3.3 第六次嘗試:使用Lambda表達(dá)式 32
2.3.4 第七次嘗試:將List類型抽象化 33
2.4 真實的例子 33
2.4.1 用Comparator來排序 33
2.4.2 用Runnable執(zhí)行代碼塊 34
2.4.3 通過Callable返回結(jié)果 35
2.4.4 GUI事件處理 35
2.5 小結(jié) 36
第 3 章 Lambda表達(dá)式 37
3.1 Lambda管中窺豹 37
3.2 在哪里以及如何使用Lambda 40
3.2.1 函數(shù)式接口 40
3.2.2 函數(shù)描述符 42
3.3 把Lambda付諸實踐:環(huán)繞執(zhí)行模式 44
3.3.1 第 1 步:記得行為參數(shù)化 44
3.3.2 第 2 步:使用函數(shù)式接口來傳遞行為 45
3.3.3 第 3 步:執(zhí)行一個行為 45
3.3.4 第 4 步:傳遞Lambda 46
3.4 使用函數(shù)式接口 47
3.4.1 Predicate 47
3.4.2 Consumer 47
3.4.3 Function 48
3.5 類型檢查、類型推斷以及限制 52
3.5.1 類型檢查 52
3.5.2 同樣的Lambda,不同的函數(shù)式接口 53
3.5.3 類型推斷 55
3.5.4 使用局部變量 56
3.6 方法引用 57
3.6.1 管中窺豹 57
3.6.2 構(gòu)造函數(shù)引用 60
3.7 Lambda和方法引用實戰(zhàn) 62
3.7.1 第 1 步:傳遞代碼 62
3.7.2 第 2 步:使用匿名類 62
3.7.3 第 3 步:使用Lambda表達(dá)式 62
3.7.4 第 4 步:使用方法引用 63
3.8 復(fù)合Lambda表達(dá)式的有用方法 63
3.8.1 比較器復(fù)合 64
3.8.2 謂詞復(fù)合 64
3.8.3 函數(shù)復(fù)合 65
3.9 數(shù)學(xué)中的類似思想 66
3.9.1 積分 66
3.9.2 與Java 8的Lambda聯(lián)系起來 68
3.10 小結(jié) 68
第二部分 使用流進(jìn)行函數(shù)式數(shù)據(jù)處理
第 4 章 引入流 72
4.1 流是什么 72
4.2 流簡介 76
4.3 流與集合 78
4.3.1 只能遍歷一次 79
4.3.2 外部迭代與內(nèi)部迭代 80
4.4 流操作 82
4.4.1 中間操作 83
4.4.2 終端操作 84
4.4.3 使用流 84
4.5 路線圖 85
4.6 小結(jié) 85
第 5 章 使用流 86
5.1 篩選 87
5.1.1 用謂詞篩選 87
5.1.2 篩選各異的元素 87
5.2 流的切片 88
5.2.1 使用謂詞對流進(jìn)行切片 88
5.2.2 截短流 90
5.2.3 跳過元素 90
5.3 映射 91
5.3.1 對流中每一個元素應(yīng)用函數(shù) 91
5.3.2 流的扁平化 92
5.4 查找和匹配 95
5.4.1 檢查謂詞是否至少匹配一個元素 95
5.4.2 檢查謂詞是否匹配所有元素 96
5.4.3 查找元素 96
5.4.4 查找第 一個元素 97
5.5 歸約 98
5.5.1 元素求和 98
5.5.2 最大值和最小值 100
5.6 付諸實踐 103
5.6.1 領(lǐng)域:交易員和交易 103
5.6.2 解答 104
5.7 數(shù)值流 106
5.7.1 原始類型流特化 107
5.7.2 數(shù)值范圍 108
5.7.3 數(shù)值流應(yīng)用:勾股數(shù) 108
5.8 構(gòu)建流 111
5.8.1 由值創(chuàng)建流 111
5.8.2 由可空對象創(chuàng)建流 111
5.8.3 由數(shù)組創(chuàng)建流 112
5.8.4 由文件生成流 112
5.8.5 由函數(shù)生成流:創(chuàng)建無限流 113
5.9 概述 116
5.10 小結(jié) 116
第 6 章 用流收集數(shù)據(jù) 118
6.1 收集器簡介 119
6.1.1 收集器用作高級歸約 119
6.1.2 預(yù)定義收集器 120
6.2 歸約和匯總 121
6.2.1 查找流中的最大值和最小值 121
6.2.2 匯總 122
6.2.3 連接字符串 123
6.2.4 廣義的歸約匯總 124
6.3 分組 127
6.3.1 操作分組的元素 128
6.3.2 多級分組 130
6.3.3 按子組收集數(shù)據(jù) 131
6.4 分區(qū) 134
6.4.1 分區(qū)的優(yōu)勢 135
6.4.2 將數(shù)字按質(zhì)數(shù)和非質(zhì)數(shù)分區(qū) 136
6.5 收集器接口 138
6.5.1 理解Collector接口聲明的方法 139
6.5.2 全部融合到一起 143
6.6 開發(fā)你自己的收集器以獲得更好的性能 144
6.6.1 僅用質(zhì)數(shù)做除數(shù) 145
6.6.2 比較收集器的性能 148
6.7 小結(jié) 150
第 7 章 并行數(shù)據(jù)處理與性能 151
7.1 并行流 152
7.1.1 將順序流轉(zhuǎn)換為并行流 52
7.1.2 測量流性能 154
7.1.3 正確使用并行流 158
7.1.4 高效使用并行流 159
7.2 分支/合并框架 161
7.2.1 使用RecursiveTask 161
7.2.2 使用分支/合并框架的最佳做法 164
7.2.3 工作竊取 165
7.3 Spliterator 166
7.3.1 拆分過程 167
7.3.2 實現(xiàn)你自己的Spliterator 168
7.4 小結(jié) 173
第三部分 使用流和Lambda進(jìn)行高效編程
第 8 章 Collection API的增強(qiáng)功能 176
8.1 集合工廠 176
8.1.1 List工廠 177
8.1.2 Set工廠 178
8.1.3 Map工廠 179
8.2 使用List和Set 180
8.2.1 removeIf方法 180
8.2.2 replaceAll方法 181
8.3 使用Map 181
8.3.1 forEach方法 182
8.3.2 排序 182
8.3.3 getOrDefault方法 183
8.3.4 計算模式 183
8.3.5 刪除模式 184
8.3.6 替換模式 185
8.3.7 merge方法 185
8.4 改進(jìn)的ConcurrentHashMap 187
8.4.1 歸約和搜索 187
8.4.2 計數(shù) 188
8.4.3 Set視圖 188
8.5 小結(jié) 188
第 9 章 重構(gòu)、測試和調(diào)試 189
9.1 為改善可讀性和靈活性重構(gòu)代碼 189
9.1.1 改善代碼的可讀性 190
9.1.2 從匿名類到Lambda表達(dá)式的轉(zhuǎn)換 190
9.1.3 從Lambda表達(dá)式到方法引用的轉(zhuǎn)換 191
9.1.4 從命令式的數(shù)據(jù)處理切換到Stream 193
9.1.5 增加代碼的靈活性 193
9.2 使用Lambda重構(gòu)面向?qū)ο蟮脑O(shè)計模式 195
9.2.1 策略模式 196
9.2.2 模板方法 197
9.2.3 觀察者模式 198
9.2.4 責(zé)任鏈模式 201
9.2.5 工廠模式 202
9.3 測試Lambda表達(dá)式 204
9.3.1 測試可見Lambda函數(shù)的行為 204
9.3.2 測試使用Lambda的方法的行為 205
9.3.3 將復(fù)雜的Lambda表達(dá)式分為不同的方法 205
9.3.4 高階函數(shù)的測試 206
9.4 調(diào)試 206
9.4.1 查看棧跟蹤 206
9.4.2 使用日志調(diào)試 208
9.5 小結(jié) 209
第 10 章 基于Lambda的領(lǐng)域特定語言 210
10.1 領(lǐng)域特定語言 212
10.1.1 DSL的優(yōu)點(diǎn)和弊端 212
10.1.2 JVM中已提供的DSL解決方案 214
10.2 現(xiàn)代Java API中的小型DSL 217
10.2.1 把Stream API當(dāng)成DSL去操作集合 219
10.2.2 將Collectors作為DSL匯總數(shù)據(jù) 220
10.3 使用Java創(chuàng)建DSL的模式與技巧 221
10.3.1 方法鏈接 224
10.3.2 使用嵌套函數(shù) 226
10.3.3 使用Lambda表達(dá)式的函數(shù)序列 228
10.3.4 把它們都放到一起 230
10.3.5 在DSL中使用方法引用 232
10.4 Java 8 DSL的實際應(yīng)用 234
10.4.1 jOOQ 235
10.4.2 Cucumber 236
10.4.3 Spring Integration 238
10.5 小結(jié) 239
第四部分 無所不在的Java
第 11 章 用Optional取代null 242
11.1 如何為缺失的值建!243
11.1.1 采用防御式檢查減少NullPointerException 243
11.1.2 null帶來的種種問題 245
11.1.3 其他語言中null的替代品 245
11.2 Optional類入門 246
11.3 應(yīng)用Optional的幾種模式 248
11.3.1 創(chuàng)建Optional對象 248
11.3.2 使用map從Optional對象中提取和轉(zhuǎn)換值 248
11.3.3 使用flatMap鏈接Optional對象 249
11.3.4 操縱由Optional對象構(gòu)成的Stream 253
11.3.5 默認(rèn)行為及解引用Optional對象 254
11.3.6 兩個Optional對象的組合 255
11.3.7 使用filter剔除特定的值 257
11.4 使用Optional的實戰(zhàn)示例 258
11.4.1 用Optional 封裝可能為null的值 259
11.4.2 異常與Optional的對比 259
11.4.3 基礎(chǔ)類型的Optional對象,以及為什么應(yīng)該避免使用它們 260
11.4.4 把所有內(nèi)容整合起來 260
11.5 小結(jié) 262
第 12 章 新的日期和時間API 263
12.1 LocalDate、LocalTime、LocalDateTime、Instant、Duration以及Period 264
12.1.1 使用LocalDate和LocalTime 264
12.1.2 合并日期和時間 265
12.1.3 機(jī)器的日期和時間格式 266
12.1.4 定義Duration或Period 267
12.2 操縱、解析和格式化日期 268
12.2.1 使用TemporalAdjuster 270
12.2.2 打印輸出及解析日期?C時間對象 272
12.3 處理不同的時區(qū)和歷法 274
12.3.1 使用時區(qū) 274
12.3.2 利用和UTC/格林尼治時間的固定偏差計算時區(qū) 275
12.3.3 使用別的日歷系統(tǒng) 276
12.4 小結(jié) 277
第 13 章 默認(rèn)方法 278
13.1 不斷演進(jìn)的API 280
13.1.1 初始版本的API 281
13.1.2 第二版API 281
13.2 概述默認(rèn)方法 283
13.3 默認(rèn)方法的使用模式 285
13.3.1 可選方法 285
13.3.2 行為的多繼承 286
13.4 解決沖突的規(guī)則 289
13.4.1 解決問題的三條規(guī)則 289
13.4.2 選擇提供了最具體實現(xiàn)的默認(rèn)方法的接口 290
13.4.3 沖突及如何顯式地消除歧義 291
13.4.4 菱形繼承問題 293
13.5 小結(jié) 294
第 14 章 Java模塊系統(tǒng) 295
14.1 模塊化的驅(qū)動力:軟件的推理 295
14.1.1 關(guān)注點(diǎn)分離 295
14.1.2 信息隱藏 296
14.1.3 Java軟件 296
14.2 為什么要設(shè)計Java模塊系統(tǒng) 297
14.2.1 模塊化的局限性 297
14.2.2 單體型的JDK 298
14.2.3 與OSGi的比較 299
14.3 Java模塊:全局視圖 300
14.4 使用Java模塊系統(tǒng)開發(fā)應(yīng)用 301
14.4.1 從頭開始搭建一個應(yīng)用 302
14.4.2 細(xì)粒度和粗粒度的模塊化 303
14.4.3 Java模塊系統(tǒng)基礎(chǔ) 303
14.5 使用多個模塊 304
14.5.1 exports子句 304
14.5.2 requires子句 305
14.5.3 命名 306
14.6 編譯及打包 306
14.7 自動模塊 310
14.8 模塊聲明及子句 311
14.8.1 requires 311
14.8.2 exports 311
14.8.3 requires的傳遞 311
14.8.4 exports to 312
14.8.5 open和opens 312
14.8.6 uses和provides 313
14.9 通過一個更復(fù)雜的例子了解更多 313
14.10 小結(jié) 314
第五部分 提升Java的并發(fā)性
第 15 章 CompletableFuture及反應(yīng)式編程背后的概念 316
15.1 為支持并發(fā)而不斷演進(jìn)的Java 318
15.1.1 線程以及更高層的抽象 319
15.1.2 執(zhí)行器和線程池 320
15.1.3 其他的線程抽象:非嵌套方法調(diào)用 322
15.1.4 你希望線程為你帶來什么 324
15.2 同步及異步API 324
15.2.1 Future風(fēng)格的API 326
15.2.2 反應(yīng)式風(fēng)格的API 327
15.2.3 有害的睡眠及其他阻塞式操作 328
15.2.4 實戰(zhàn)驗證 329
15.2.5 如何使用異步API進(jìn)行異常處理 330
15.3 線框?C管道模型 331
15.4 為并發(fā)而生的CompletableFuture和結(jié)合器 332
15.5 發(fā)布?C訂閱以及反應(yīng)式編程 335
15.5.1 示例:對兩個流求和 337
15.5.2 背壓 341
15.5.3 一種簡單的真實背壓 341
15.6 反應(yīng)式系統(tǒng)和反應(yīng)式編程 342
15.7 路線圖 342
15.8 小結(jié) 343
第 16 章 CompletableFuture:組合式異步編程 344
16.1 Future接口 344
16.1.1 Future接口的局限性 346
16.1.2 使用CompletableFuture構(gòu)建異步應(yīng)用 346
16.2 實現(xiàn)異步API 347
16.2.1 將同步方法轉(zhuǎn)換為異步方法 348
16.2.2 錯誤處理 350
16.3 讓你的代碼免受阻塞之苦 352
16.3.1 使用并行流對請求進(jìn)行并行操作 353
16.3.2 使用CompletableFuture發(fā)起異步請求 353
16.3.3 尋找更好的方案 355
16.3.4 使用定制的執(zhí)行器 356
16.4 對多個異步任務(wù)進(jìn)行流水線操作 358
16.4.1 實現(xiàn)折扣服務(wù) 358
16.4.2 使用Discount服務(wù) 359
16.4.3 構(gòu)造同步和異步操作 360
16.4.4 將兩個CompletableFuture對象整合起來,無論它們是否存在依賴 363
16.4.5 對Future和Completable-Future 的回顧 364
16.4.6 高效地使用超時機(jī)制 365
16.5 響應(yīng)CompletableFuture的completion事件 366
16.5.1 對最佳價格查詢器應(yīng)用的優(yōu)化 367
16.5.2 付諸實踐 368
16.6 路線圖 369
16.7 小結(jié) 369
第 17 章 反應(yīng)式編程 370
17.1 反應(yīng)式宣言 371
17.1.1 應(yīng)用層的反應(yīng)式編程 371
17.1.2 反應(yīng)式系統(tǒng) 373
17.2 反應(yīng)式流以及Flow API 373
17.2.1 Flow類 374
17.2.2 創(chuàng)建你的第 一個反應(yīng)式應(yīng)用 377
17.2.3 使用Processor轉(zhuǎn)換數(shù)據(jù) 381
17.2.4 為什么Java并未提供Flow API的實現(xiàn) 383
17.3 使用反應(yīng)式庫RxJava 384
17.3.1 創(chuàng)建和使用Observable 385
17.3.2 轉(zhuǎn)換及整合多個Observable 392
第六部分 函數(shù)式編程以及Java未來的演進(jìn)
第 18 章 函數(shù)式的思考 396
18.1 實現(xiàn)和維護(hù)系統(tǒng) 396
18.1.1 共享的可變數(shù)據(jù) 397
18.1.2 聲明式編程 398
18.1.3 為什么要采用函數(shù)式編程 399
18.2 什么是函數(shù)式編程 399
18.2.1 函數(shù)式Java編程 400
18.2.2 引用透明性 402
18.2.3 面向?qū)ο蟮木幊毯秃瘮?shù)式編程的對比 402
18.2.4 函數(shù)式編程實戰(zhàn) 403
18.3 遞歸和迭代 405
18.4 小結(jié) 408
第 19 章 函數(shù)式編程的技巧 409
19.1 無處不在的函數(shù) 409
19.1.1 高階函數(shù) 410
19.1.2 柯里化 411
19.2 持久化數(shù)據(jù)結(jié)構(gòu) 412
19.2.1 破壞式更新和函數(shù)式更新的比較 413
19.2.2 另一個使用Tree的例子 415
19.2.3 采用函數(shù)式的方法 416
19.3 Stream的延遲計算 418
19.3.1 自定義的Stream 418
19.3.2 創(chuàng)建你自己的延遲列表 420
19.4 模式匹配 425
19.4.1 訪問者模式 425
19.4.2 用模式匹配力挽狂瀾 426
19.5 雜項 429
19.5.1 緩存或記憶表 429
19.5.2 返回同樣的對象意味著什么 430
19.5.3 結(jié)合器 431
19.6 小結(jié) 432
第 20 章 面向?qū)ο蠛秃瘮?shù)式編程的混合:Java和Scala的比較 433
20.1 Scala簡介 434
20.1.1 你好,啤酒 434
20.1.2 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu):List、Set、Map、Tuple、Stream以及Option 436
20.2 函數(shù) 440
20.2.1 Scala中的一等函數(shù) 441
20.2.2 匿名函數(shù)和閉包 442
20.2.3 柯里化 443
20.3 類和trait 444
20.3.1 更加簡潔的Scala類 445
20.3.2 Scala的trait與Java 8的接口對比 446
20.4 小結(jié) 447
第 21 章 結(jié)論以及Java的未來 448
21.1 回顧Java 8的語言特性 448
21.1.1 行為參數(shù)化(Lambda以及方法引用) 449
21.1.2 流 449
21.1.3 CompletableFuture 450
21.1.4 Optional 450
21.1.5 Flow API 451
21.1.6 默認(rèn)方法 451
21.2 Java 9的模塊系統(tǒng) 451
21.3 Java 10的局部變量類型推斷 453
21.4 Java的未來 454
21.4.1 聲明處型變 454
21.4.2 模式匹配 454
21.4.3 更加豐富的泛型形式 455
21.4.4 對不變性的更深層支持 457
21.4.5 值類型 458
21.5 讓Java發(fā)展得更快 461
21.6 寫在最后的話 462
附錄A 其他語言特性的更新 463
附錄B 其他類庫的更新 467
附錄C 如何以并發(fā)方式在同一個流上執(zhí)行多種操作 475
附錄D Lambda表達(dá)式和JVM字節(jié)碼 483