本目錄收錄《Java 程式設計完整學習教材》進階篇 ch01~ch08 全部 82 個範例,
皆可獨立編譯(已於 OpenJDK 21 驗證),並保留書中的繁體中文教學註解。
每個檔案第一行的 // 出處:… 註明對應的章節。
執行方式
cd code
./run.sh advanced/<章節目錄> <主類別名>
# 例如:
./run.sh advanced/ch01-lambda-functional LambdaDemo
./run.sh advanced/ch08-design-patterns-modern-java ExprEval
需 JDK 21(虛擬執行緒、switch 模式匹配與 record 解構為 21 的正式功能)。
本冊特殊範例注意事項
- 多執行緒範例(ch03、ch04):輸出的交錯順序、執行緒與任務的對應
每次執行都可能不同,屬預期行為;書中輸出僅為其中一種可能。
- 死結範例
DeadlockDemo(ch03):本範例會永久卡住,屬預期行為,
請以 Ctrl+C 結束。可另開終端機用 jps 找出程序號、jstack <pid>
觀察死結報告(會印出 Found one Java-level deadlock,即第 6 章
6.7 節的示範)。
- OOM 示範
HeapOOM(ch06):請用小堆積執行,建議
java -Xmx64m -XX:+UseSerialGC HeapOOM。詳見 ch06 備註。
- 網路範例(ch07):伺服器與用戶端要開兩個終端機分別執行;
macOS 若開啟「AirPlay 接收器」會佔用 TCP 5000 埠,導致
EchoServer/PooledEchoServer 拋出 BindException: Address already
in use,請先到系統設定關閉 AirPlay 接收器(或自行改埠測試)。
- HttpClient 範例(ch07):實際執行需要網際網路連線,本目錄僅驗證
編譯;離線執行會拋出連線例外。
- JDBC 範例(ch07):
java.sql 為 JDK 內建,編譯不需任何依賴;
實際執行需先下載 SQLite JDBC 驅動(org.xerial:sqlite-jdbc)JAR,
再以 java -cp ".:sqlite-jdbc-<版本>.jar" JdbcCrud 執行(或把連線
字串改為 MySQL)。書中的執行結果為示意輸出。
ch01 Lambda 與函數式程式設計(13 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| NamedClassDemo.java |
具名類別實作 Runnable |
run.sh |
|
| AnonymousClassDemo.java |
匿名類別實作 Runnable |
run.sh |
|
| LambdaDemo.java |
Lambda 實作 Runnable |
run.sh |
|
| CalculatorDemo.java |
自訂函數式介面與預設方法 |
run.sh |
書中標題為 Calculator.java,因公開類別名而改名 |
| FunctionDemo.java |
Function 的 apply/andThen/compose |
run.sh |
|
| PredicateDemo.java |
Predicate 的 test/and/or/negate |
run.sh |
|
| ConsumerSupplierDemo.java |
Consumer 與 Supplier |
run.sh |
|
| MethodRefDemo.java |
四種方法參考 |
run.sh |
|
| CaptureDemo.java |
變數捕獲與 effectively final |
run.sh |
|
| ComparatorDemo.java |
Comparator 多鍵排序 |
run.sh |
部門升冪依 Unicode 碼位「研發」在「行銷」前,與書中輸出順序不同(見文末) |
| OptionalBasics.java |
Optional 建立與 map/filter/orElse |
run.sh |
|
| OrElseVsOrElseGet.java |
orElse 與 orElseGet 求值時機 |
run.sh |
|
| PasswordValidator.java |
Predicate 組合驗證器 |
run.sh |
|
ch02 Stream API(12 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| ImperativeStyle.java |
命令式寫法對照組 |
run.sh |
|
| DeclarativeStyle.java |
宣告式(Stream)寫法 |
run.sh |
|
| CreateStream.java |
六種建立 Stream 的方式 |
run.sh |
|
| FlatMapDemo.java |
flatMap 攤平巢狀結構 |
run.sh |
|
| LazyEvaluation.java |
peek 觀察惰性求值 |
run.sh |
|
| TerminalOps.java |
比對/搜尋/極值終端操作 |
run.sh |
|
| ReduceDemo.java |
reduce 三種形式 |
run.sh |
|
| CollectorsBasics.java |
joining 與 toMap 合併函式 |
run.sh |
|
| GroupingDemo.java |
groupingBy 單層/下游/巢狀 |
run.sh |
Map 印出順序不保證,內容與書中一致 |
| PrimitiveStream.java |
IntStream 與 summaryStatistics |
run.sh |
|
| ParallelPitfall.java |
平行流共享可變狀態的錯誤 |
run.sh |
錯誤寫法筆數每次不同(甚至可能拋例外),屬預期的反面教材 |
| EmployeeAnalytics.java |
員工資料多維度分析 |
run.sh |
Map 印出順序不保證 |
ch03 多執行緒基礎(11 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| ThreadBySubclass.java |
繼承 Thread 建立執行緒 |
run.sh |
|
| ThreadByRunnable.java |
Runnable 與 Lambda 寫法 |
run.sh |
兩行輸出順序不定 |
| ThreadStateDemo.java |
觀察執行緒六種狀態 |
run.sh |
|
| JoinDemo.java |
join 等待工作完成 |
run.sh |
|
| DaemonDemo.java |
守護執行緒背景心跳 |
run.sh |
心跳次數視時間而定 |
| InterruptDemo.java |
正確回應中斷 |
run.sh |
「工作中…」次數視時間而定 |
| RaceCondition.java |
競態條件(遺失更新) |
run.sh |
實際值每次不同且小於 200000,屬預期 |
| SyncCounter.java |
synchronized 修正競態 |
run.sh |
|
| VolatileDemo.java |
volatile 可見性 |
run.sh |
累計值每次不同 |
| ProducerConsumer.java |
wait/notify 生產者消費者 |
run.sh |
交錯順序每次不同,總量各 5 |
| DeadlockDemo.java |
交叉取鎖造成死結 |
run.sh |
會永久卡住,屬預期行為,Ctrl+C 結束;可用 jstack 觀察死結報告 |
ch04 並行程式設計進階(12 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| ExecutorBasics.java |
執行緒池提交任務與標準關閉 |
run.sh |
任務與執行緒對應順序不定 |
| CustomPool.java |
手動配置 ThreadPoolExecutor |
run.sh |
排程順序不定 |
| FutureDemo.java |
Callable 與 Future |
run.sh |
|
| CompletableFutureBasics.java |
thenApply/thenCompose/thenCombine |
run.sh |
|
| CompletableFutureError.java |
exceptionally 例外處理 |
run.sh |
|
| AsyncPipeline.java |
並行查詢合併與耗時量測 |
run.sh |
總耗時約 200~300 毫秒 |
| AtomicCounter.java |
AtomicInteger 免鎖計數 |
run.sh |
|
| TryLockDemo.java |
tryLock 帶逾時取鎖 |
run.sh |
實測兩執行緒會先後取得鎖,與書中輸出不同(見文末) |
| ConcurrentMapDemo.java |
ConcurrentHashMap 的 merge |
run.sh |
|
| BlockingQueueDemo.java |
BlockingQueue 生產者消費者 |
run.sh |
交錯順序每次不同 |
| CountDownLatchDemo.java |
CountDownLatch 等待多工 |
run.sh |
|
| VirtualThreadDemo.java |
虛擬執行緒(Java 21) |
run.sh |
完成順序不固定 |
ch05 反射與標註(7 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| GetClassObject.java |
三種取得 Class 物件 |
run.sh |
|
| InspectClass.java |
走訪欄位與方法 |
run.sh |
getDeclaredMethods 順序不保證,方法列出順序可能與書中相反 |
| DynamicInvoke.java |
動態建立實體/呼叫/改私有欄位 |
run.sh |
|
| Column.java |
自訂標註 @Column 的定義 |
僅編譯(無 main) |
書中 5.6 節的定義列表;執行期讀取見 ReadAnnotation |
| ReadAnnotation.java |
反射讀取欄位標註 |
run.sh |
|
| MiniTest.java |
迷你測試框架(仿 JUnit) |
run.sh |
方法掃描順序不保證 |
| MiniInjector.java |
迷你依賴注入(仿 Spring) |
run.sh |
|
ch06 JVM 深入剖析(6 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| ClassInit.java |
類別初始化觸發時機 |
run.sh |
|
| ClassLoaderDemo.java |
類別載入器階層 |
run.sh |
@ 後的雜湊值因執行而異 |
| StackOverflow.java |
無窮遞迴撐爆堆疊 |
run.sh |
深度視 -Xss 而定(實測約 1.5 萬~2 萬);可用 java -Xss256k 觀察更小深度 |
| HeapOOM.java |
堆積溢位示範 |
java -Xmx64m -XX:+UseSerialGC HeapOOM |
用 Serial/Parallel GC 可看到書中訊息(實測約 56~60 MB);JDK 21 預設 G1 下 catch 內字串串接常再度 OOM,訊息印不出、直接顯示未捕捉的 OutOfMemoryError(教學點仍成立)。-Xmx16m 亦可快速觀察 |
| ReferenceDemo.java |
弱引用被 GC 回收 |
run.sh |
|
| MemoryLeak.java |
static 集合造成洩漏 |
run.sh |
|
6.7 節的 jps/jstack 示範沒有獨立程式,請對 ch03 的 DeadlockDemo
操作即可重現(輸出中的監視器位址等因環境而異)。GC 日誌示範可用
java -Xlog:gc 搭配任一範例觀察,輸出因環境而異。
ch07 網路程式設計與 JDBC(12 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| InetAddressDemo.java |
查詢本機與主機 IP |
run.sh |
輸出為本機環境值,與書中示意不同屬正常 |
| EchoServer.java |
單執行緒回聲伺服器(5000 埠) |
見下方兩終端機步驟 |
macOS 需先關閉 AirPlay 接收器 |
| EchoClient.java |
回聲用戶端 |
見下方兩終端機步驟 |
|
| PooledEchoServer.java |
執行緒池回聲伺服器(5000 埠) |
同上,可多開用戶端 |
無限迴圈,Ctrl+C 結束 |
| ChatServer.java |
群聊廣播伺服器(6000 埠) |
伺服器 + 多個 nc localhost 6000 |
無限迴圈,Ctrl+C 結束;已實測兩用戶端廣播 |
| UdpDemo.java |
UDP 收發(7000 埠,單程式) |
run.sh |
AirPlay 佔用的是 TCP 7000,不影響本範例的 UDP |
| HttpClientDemo.java |
HttpClient 同步/非同步請求 |
需網路連線 |
僅驗證編譯;離線會拋連線例外 |
| JdbcCrud.java |
JDBC 建表與 CRUD |
需 SQLite 驅動 |
java -cp ".:sqlite-jdbc-<版本>.jar" JdbcCrud |
| SqlInjection.java |
SQL 注入示範(僅字串) |
run.sh |
不需資料庫 |
| PreparedStatementDemo.java |
參數化查詢 |
需 SQLite 驅動 |
先跑 JdbcCrud 建表 |
| TransferDemo.java |
交易與回滾 |
需 SQLite 驅動 |
需先自建 account 表 |
| StudentDao.java |
DAO 模式與批次寫入 |
僅編譯(無 main) |
書中列表即無 main,展示 DAO 結構;書中輸出為呼叫 saveAll 的示意 |
Echo 範例的兩終端機步驟(伺服器服務完一條連線即結束):
# 終端機 1:啟動伺服器(macOS 請先關閉 AirPlay 接收器)
./run.sh advanced/ch07-network-jdbc EchoServer
# 終端機 2:啟動用戶端,送出兩行訊息並印出回聲
./run.sh advanced/ch07-network-jdbc EchoClient
群聊範例:終端機 1 跑 ChatServer,終端機 2、3 各跑
nc localhost 6000,任一邊輸入文字,所有用戶端都會收到。
ch08 設計模式與現代 Java(9 個)
| 檔案 |
內容說明 |
執行方式 |
備註 |
| OpenClosed.java |
開放封閉原則 |
run.sh |
|
| Singletons.java |
單例多種寫法(餓漢/雙重檢查/靜態內部類別) |
run.sh |
三種寫法為同檔巢狀類別,無需分目錄 |
| FactoryMethod.java |
工廠方法模式 |
run.sh |
|
| BuilderDemo.java |
建造者模式 |
run.sh |
|
| StrategyDemo.java |
策略模式(Lambda 版) |
run.sh |
|
| ObserverDemo.java |
觀察者模式 |
run.sh |
|
| DecoratorDemo.java |
裝飾者模式 |
run.sh |
|
| RecordDemo.java |
record 與 text block |
run.sh |
|
| ExprEval.java |
sealed + record + switch 模式匹配 |
run.sh |
需 JDK 21 |
未抽出片段
無。書中 82 個程式列表(javacode 區塊)全數抽出;其中 Column.java
與 StudentDao.java 依書中原樣無 main 方法,屬「僅編譯」的結構示範。
內文以文字描述的零星程式片段(如 Stream 重複消費的條列、jstack 指令
操作)不屬程式列表,未列入抽出範圍。
與書中輸出的已知差異
- ch01
ComparatorDemo:部門「升冪」依 Java 字串自然排序
(Unicode 碼位),「研發」(U+7814) 排在「行銷」(U+884C) 之前;
實際輸出研發組在前,書中誤將行銷組排在前。
- ch04
TryLockDemo:持鎖時間 300 毫秒短於 tryLock 逾時
500 毫秒,後到的執行緒會等到鎖釋放後成功取得;實測(多次)皆為
「A 取得鎖/B 取得鎖」先後出現,書中「B 放棄取鎖」在此參數下
不會發生。
- ch06
HeapOOM:JDK 21 預設 G1 下,catch 區塊內的字串串接
會再度 OOM,導致書中訊息未印出;改用 -XX:+UseSerialGC 可重現
書中輸出。
- 其餘差異皆屬書中已註明的非決定性(執行緒交錯、Map 順序、
反射順序、環境相關數值),內容語意與書中一致。