Java程序員修煉之道(第2版) The Well-Grounded Java Developer, Second Edition

[英] 本傑明 · J. 埃文斯(Benjamin J. Evans) [美] 傑森 · 克拉克(Jason Clark) [荷] 馬丁 · 韋爾伯格(Martijn Verburg)

  • Java程序員修煉之道(第2版)-preview-1
  • Java程序員修煉之道(第2版)-preview-2
Java程序員修煉之道(第2版)-preview-1

相關主題

商品描述

《Java 程序員修煉之道(第2 版)》是為有誌成為卓越 Java 開發者的人編寫的實用指南。相比於第 1 版,第 2 版擴展了內容,深入探討了 Java 8、11 及更高版本的特性。本書不僅覆蓋了 Java 語言本身的新特性,還引入了與現代開發實踐息息相關的主題,包括函數式編程、並發、多語言編程及容器化部署等。本書的核心目標是幫助開發者建立紮實的基礎,掌握 Java 語言和 JVM 平臺的深層知識,同時引導讀者了解 Java 生態中的非 Java 語言,如 Kotlin 和 Clojure。通過對 Java 語言核心原理的學習,讀者將掌握如何高效地使用 Java,如何應對日益復雜的開發環境,並理解平臺的未來演化方向。

作者簡介

本傑明·J. 埃文斯(Benjamin J. Evans)

全球 Java 領域最具影響力的技術專家之一。作為 Java Champion,他在 Java 社區享有崇高聲譽,參與制定Java標準,直接影響 Java 生態的發展方向。目前擔任紅帽公司首席軟件工程師,致力於企業級 Java 解決方案的創新與優化。

 

傑森·克拉克(Jason Clark)

New Relic 公司首席工程師和架構師,專註於高性能分布式系統、雲計算和 Java 生態的優化。他在企業級軟件開發、微服務架構和 JVM 深度優化方面有豐富的經驗。

 

馬丁·韋爾伯格(Martijn Verburg)

Java 生態領域的頂尖技術領袖之一,AdoptOpenJDK(現為 Eclipse Adoptium) 聯合創始人,現任微軟首席工程組經理(Java & Golang)。同時,馬丁是倫敦 Java 社區(LJC)的聯合領導者,致力於推動 Java 技術在全球開發者社區中的普及與創新。他在多個 Java 規範組織中擔任重要角色,直接參與 Java 標準的制定與演進。

目錄大綱

第 一部分 從 Java 8 到 Java 17 及更高版本

第 1章 現代 Java 介紹 2

1.1 Java 語言和 Java 平臺 2

1.2 Java 的新發布模型 4

1.3 類型推斷增強(var 關鍵字) 7

1.4 語言和平臺的更改 10

1.4.1 撒點兒糖 11

1.4.2 語言更改 11

1.4.3 JSR 和 JEP 12

1.4.4 孵化特性和預覽特性 12

1.5 Java 11 中的小變更 13

1.5.1 集合工廠(JEP 213) 13

1.5.2 移除企業版模塊(JEP 320) 14

1.5.3 HTTP/2(Java 11) 15

1.5.4 單文件源代碼程序(JEP 330) 19

小結 21

第 2章 Java 模塊 22

2.1 場景設置 22

2.1.1 Jigsaw 項目 23

2.1.2 模塊圖 26

2.1.3 保護內部 27

2.1.4 新的訪問控制語義 28

2.2 模塊的基本語法 29

2.2.1 導出和依賴 30

2.2.2 傳遞性 31

2.3 模塊加載 32

2.3.1 平臺模塊 32

2.3.2 應用模塊 33

2.3.3 自動模塊 33

2.3.4 未命名模塊 34

2.4 構建模塊化應用程序 34

2.4.1 模塊的命令行開關 35

2.4.2 運行模塊化應用 37

2.4.3 模塊與反射 38

2.5 模塊架構 39

2.5.1 拆分包 40

2.5.2 Java 8 運行時精簡模式 40

2.5.3 多版本 JAR 42

2.6 超越模塊 45

小結 46

第3章 Java 17 47

3.1 文本塊 47

3.2 switch 表達式 48

3.3 record 51

3.3.1 名義類型 56

3.3.2 緊湊記錄構造器 58

3.4 sealed 59

3.5 instanceof 的新用法 63

3.6 模式匹配和預覽特性 65

小結 67

第二部分 內部原理

第4章 類文件和字節碼 70

4.1 類加載和類對象 71

4.1.1 加載和鏈接 72

4.1.2 類對象 73

4.2 類加載器 74

4.2.1 自定義類加載器 76

4.2.2 模塊和類加載 82

4.3 檢查類文件 82

4.3.1 javap 簡介 83

4.3.2 方法簽名的內部表示形式 83

4.3.3 常量池 84

4.4 字節碼 87

4.4.1 分解類文件 87

4.4.2 運行時環境 89

4.4.3 操作碼介紹 91

4.4.4 加載和存儲操作碼 92

4.4.5 數學運算操作碼 93

4.4.6 流程控制操作碼 93

4.4.7 調用操作碼 94

4.4.8 平臺操作碼 97

4.4.9 操作碼的快捷形式 97

4.5 反射 98

4.5.1 反射概述 98

4.5.2 類加載與反射 100

4.5.3 反射的局限性 101

小結 102

第5章 Java 並發基礎 103

5.1 並發理論 104

5.1.1 我已經了解線程了 104

5.1.2 硬件 104

5.1.3 Amdahl 定律 105

5.1.4 Java 的線程模型 106

5.1.5 經驗教訓 107

5.2 設計原則 107

5.2.1 安全性 107

5.2.2 活躍度 108

5.2.3 性能 109

5.2.4 重用性 109

5.2.5 這些設計原則為何以及如何

相互沖突 109

5.2.6 系統開銷之源 110

5.3 塊結構並發 110

5.3.1 同步與鎖 111

5.3.2 線程的狀態模型 112

5.3.3 完全同步對象 113

5.3.4 死鎖 114

5.3.5 為什麼要同步 117

5.3.6 volatile 關鍵字 118

5.3.7 Thread 類的狀態和方法 119

5.3.8 不變性 124

5.4 Java 內存模型 128

5.5 通過字節碼理解並發 129

5.5.1 更新丟失 131

5.5.2 同步的字節碼表示 133

5.5.3 同步方法 136

5.5.4 非同步讀取 137

5.5.5 重溫死鎖 139

5.5.6 重溫死鎖解決方案 141

5.5.7 易失性訪問 145

小結 147

第6章 JDK 並發庫 148

6.1 現代並發程序的構建塊 148

6.2 原子類 149

6.3 鎖 150

6.4 CountDownLatch 152

6.5 ConcurrentHashMap 154

6.5.1 簡化版 HashMap 154

6.5.2 Dictionary 的局限性 157

6.5.3 並發 Dictionary 158

6.5.4 使用 ConcurrentHashMap 160

6.6 CopyOnWriteArrayList 162

6.7 阻塞隊列 165

6.7.1 使用 BlockingQueue API 170

6.7.2 使用工作單元 171

6.8 Future 172

6.9 任務與執行 175

6.9.1 任務建模 176

6.9.2 執行器 177

6.9.3 單線程執行器 178

6.9.4 大小固定的線程池 178

6.9.5 緩存線程池 179

6.9.6 ScheduledThreadPool-Executor 180

小結 181

第7章 理解 Java 性能 182

7.1 性能術語:基本定義 184

7.1.1 時延 184

7.1.2 吞吐量 185

7.1.3 利用率 185

7.1.4 效率 185

7.1.5 容量 185

7.1.6 可擴展性 185

7.1.7 退化 185

7.2 性能分析的實用方法 186

7.2.1 知道自己在測量什麼 186

7.2.2 了解如何進行測量 187

7.2.3 知道性能目標是什麼 188

7.2.4 知道什麼時候停止 188

7.2.5 了解實現更高性能的成本 189

7.2.6 了解過早優化的危險 189

7.3 出了什麼問題,我們為什麼要關心 190

7.3.1 摩爾定律 190

7.3.2 理解內存延遲層級 192

7.4 Java 性能調優為什麼這麼難 193

7.4.1 時間在性能調優中的作用 194

7.4.2 理解緩存未命中 195

7.5 垃圾收集 196

7.5.1 基礎知識 197

7.5.2 標記-清除 197

7.5.3 內存區域 199

7.5.4 新生代垃圾收集 199

7.5.5 老年代垃圾收集 200

7.5.6 安全點 200

7.5.7 G1:Java 的默認垃圾收集器 200

7.5.8 並行收集器 202

7.5.9 GC 配置參數 203

7.6 使用 HotSpot 進行 JIT 編譯 204

7.6.1 為什麼要動態編譯 205

7.6.2 HotSpot 簡介 205

7.6.3 內聯方法 206

7.6.4 動態編譯和單態分派 207

7.6.5 理解編譯日誌 207

7.6.6 逆優化 208

7.7 JDK 飛行記錄器 209

7.7.1 JFR 209

7.7.2 JMC 210

小結 215

第三部分 JVM 上的多語言編程

第8章 JVM 語言 218

8.1 語言生態學 218

8.1.1 解釋型語言與編譯型語言 219

8.1.2 動態類型語言與靜態類型語言 219

8.1.3 命令式語言與函數式語言 220

8.1.4 對現有語言的重新實現與原始 JVM 語言 221

8.2 JVM 上的多語言編程 222

8.2.1 為什麼使用非 Java 語言 223

8.2.2 新興語言 225

8.2.3 那些我們沒有選擇的語言 226

8.3 如何為項目選擇非 Java 語言 227

8.3.1 項目域的風險承受能力是高還是低 228

8.3.2 該語言與 Java 的互操作性如何 228

8.3.3 這門語言是否有良好的工具和測試支持 229

8.3.4 這門語言有多難學 229

8.3.5 使用這門語言的開發者多嗎 229

8.4 JVM 對其他語言的支持 230

8.4.1 性能 230

8.4.2 非 Java 語言的運行時環境 231

8.4.3 編譯器虛構 231

小結 233

第9章 Kotlin 234

9.1 為什麼使用 Kotlin 234

9.2 便利和簡潔 235

9.2.1 從少開始 235

9.2.2 變量 236

9.2.3 相等性 236

9.2.4 函數 237

9.2.5 集合 240

9.2.6 表達自己 242

9.3 對類和對象的不同看法 244

9.4 安全 250

9.4.1 空安全 250

9.4.2 智能轉型 251

9.5 並發 253

9.6 與 Java 的互操作性 256

小結 259

第 10章 Clojure:編程新視角 260

10.1 介紹 Clojure 261

10.1.1 在 Clojure 中實現 Hello

World 262

10.1.2 REPL 入門 264

10.1.3 犯錯 265

10.1.4 學著去愛括號 268

10.2 尋找 Clojure:語法和語義 269

10.2.1 特殊形式訓練營 269

10.2.2 列表、向量、映射和集合 271

10.2.3 算術、相等和其他操作 274

10.2.4 使用函數 275

10.2.5 Clojure 中的循環 278

10.2.6 讀取器宏和派發器 279

10.3 函數式編程和閉包 281

10.4 Clojure 序列 282

10.5 Clojure 和 Java 的互操作 287

10.5.1 從 Clojure 中調用 Java 288

10.5.2 Clojure 調用的本質 288

10.5.3 Clojure 值的 Java 類型 289

10.5.4 使用 Clojure 代理 290

10.5.5 使用 REPL 進行探索式編程 290

10.5.6 在 Java 中使用 Clojure 291

10.6 宏 292

小結 296

第四部分 構建和運行 Java 應用

第 11章 構建工具 Gradle 和 Maven 298

11.1 為什麼構建工具對優秀的程序員至關重要 298

11.1.1 自動化煩瑣的操作 298

11.1.2 管理依賴 299

11.1.3 確保開發者間的一致性 302

11.2 Maven 303

11.2.1 構建生命周期 303

11.2.2 命令 /POM 概述 304

11.2.3 構建 305

11.2.4 控制清單文件 306

11.2.5 添加多語言支持 307

11.2.6 測試 310

11.2.7 依賴管理 313

11.2.8 評估 316

11.2.9 超越 Java 8 317

11.2.10 如何在 Maven 中使用不同版本的 JAR 318

11.2.11 Maven 與模塊 321

11.2.12 編寫 Maven 插件 324

11.3 Gradle 327

11.3.1 安裝 Gradle 327

11.3.2 任務 328

11.3.3 腳本 329

11.3.4 使用插件 330

11.3.5 構建 331

11.3.6 避免工作 333

11.3.7 Gradle 中的依賴 334

11.3.8 增加對 Kotlin 的支持 338

11.3.9 測試 339

11.3.10 自動化靜態分析 340

11.3.11 超越 Java 8 341

11.3.12 通過 Gradle 使用模塊 341

11.3.13 定制化 347

小結 350

第 12章 在容器中運行 Java 351

12.1 為什麼容器對優秀的 Java 程序員至關重要 351

12.1.1 操作系統、虛擬機、容器的區別與聯系 351

12.1.2 容器的優勢 353

12.1.3 容器的缺點 354

12.2 容器基礎 355

12.2.1 構建容器鏡像 355

12.2.2 運行 Docker 容器 358

12.3 使用 Docker 開發 Java 應用程序 360

12.3.1 選擇基礎鏡像 360

12.3.2 使用 Gradle 構建鏡像 361

12.3.3 在容器中執行構建 362

12.3.4 端口與主機 364

12.3.5 使用 Docker Compose 進行本地開發 366

12.3.6 在容器中調試 369

12.3.7 容器中的日誌 371

12.4 Kubernetes 372

12.5 可觀測性與性能 379

12.5.1 可觀測性 379

12.5.2 容器中的性能 381

小結 382

第 13章 測試基礎 383

13.1 為什麼要測試 383

13.2 如何開展測試 384

13.3 測試驅動開發 386

13.3.1 TDD 概述 387

13.3.2 一個單一用例的 TDD 示例 388

13.4 測試替身 393

13.4.1 Dummy 對象 394

13.4.2 Stub 對象 396

13.4.3 Fake 對象 398

13.4.4 Mock 對象 400

13.4.5 Mock 的問題 401

13.5 從 JUnit 4 到 JUnit 5 402

小結 408

第 14章 測試不止 JUnit 409

14.1 使用 Testcontainers 進行集成測試 409

14.1.1 安裝 testcontainers 庫 409

14.1.2 Redis 示例 410

14.1.3 收集容器的日誌 413

14.1.4 Postgres 示例 414

14.1.5 使用 Selenium 進行端到端測試的示例 416

14.2 利用 Spek 和 Kotlin 規範測試風格 418

14.3 使用 Clojure 進行基於屬性的測試 423

14.3.1 clojure.test 423

14.3.2 closure.spec 425

14.3.3 test.check 428

14.3.4 clojure.spec 和test.check 433

小結 434

第五部分 Java世界的前沿展望

第 15章 高級函數式編程 436

15.1 函數式編程的概念 436

15.1.1 純函數 437

15.1.2 不可變性 437

15.1.3 高階函數 437

15.1.4 遞歸 438

15.1.5 閉包 438

15.1.6 惰性求值 439

15.1.7 柯裏化與部分執行 439

15.2 Java 作為一門函數式語言的局限性 440

15.2.1 純函數 440

15.2.2 可變性 441

15.2.3 高階函數 443

15.2.4 遞歸 444

15.2.5 閉包 447

15.2.6 惰性求值 448

15.2.7 柯裏化與部分執行 450

15.2.8 Java 的類型系統與集合類型 450

15.3 Kotlin 中的函數式編程 452

15.3.1 純函數及高階函數 452

15.3.2 閉包 453

15.3.3 柯裏化與部分執行 454

15.3.4 不可變性 455

15.3.5 尾遞歸 458

15.3.6 惰性求值 461

15.3.7 序列 462

15.4 Clojure 的函數式編程 466

15.4.1 推導式 466

15.4.2 惰性序列 467

15.4.3 Clojure 中的柯裏化 469

小結 470

第 16章 高級並發程序設計 471

16.1 Fork/Join 框架 471

16.1.1 一個簡單的 Fork/Join應用示例 472

16.1.2 通過 Fork/Join 框架將問題處理並行化 475

16.1.3 工作竊取算法 476

16.2 並發與函數式編程 477

16.2.1 回顧 CompletableFuture 477

16.2.2 並行流 481

16.3 深入了解 Kotlin 協程的實現原理 482

16.3.1 協程的工作原理 482

16.3.2 協程的作用域及調度 487

16.4 Clojure 中的並發實踐 489

16.4.1 持久化數據結構 490

16.4.2 Future 和 pcall 495

16.4.3 軟件事務內存 497

16.4.4 代理 500

小結 501

第 17章 現代內核 503

17.1 JVM 內核概述 503

17.1.1 調用虛方法 504

17.1.2 調用接口方法 507

17.1.3 調用“特殊”方法 508

17.1.4 final 方法 509

17.2 反射的內部機制 510

17.3 方法句柄 514

17.3.1 MethodHandle 514

17.3.2 MethodType 516

17.3.3 查找方法句柄 516

17.3.4 反射、代理和方法句柄 517

17.4 動態調用 519

17.5 JVM 內核的最新變化 523

17.5.1 字符串連接 523

17.5.2 壓縮字符串 525

17.5.3 Nestmates 527

17.6 Unsafe 類 529

17.7 用支持的 API 替換 Unsafe 533

17.7.1 VarHandles 534

17.7.2 隱藏類 535

小結 537

第 18章 Java 的未來 538

18.1 項目 Amber 538

18.2 項目 Panama 540

18.3 項目 Loom 546

18.3.1 虛擬線程 549

18.3.2 線程構建器 550

18.3.3 使用虛擬線程編程 551

18.3.4 項目 Loom 什麼時候發布 552

18.4 項目 Valhalla 553

18.4.1 改變語言模型 556

18.4.2 值對象帶來的影響 557

18.4.3 回顧泛型 559

18.5 Java 18 559

小結 560

附錄A 選擇 Java 版本 561

附錄B 回顧 Java 8 中的流 564