高中時候自學 Java,那時還在用 Java 6 / 7。寫的東西不外乎 Swing 視窗程式,每次想傳一個小函式進去都要寫一大坨 anonymous inner class,現在回頭看簡直是用石器時代的工具在蓋房子。後來大學接觸 Java 8,第一次寫出 list.stream().filter(...).map(...).collect(...) 那種一行流水帳的時候,整個世界觀都打開了,原來 Java 也能寫得這麼乾淨。
從那之後 Java 每兩三年就換一個 LTS,一回頭就到 25 了。這篇把 Java 8 → 11 → 17 → 21 → 25 五個 LTS 整段補完,每個版本帶來什麼語言層級的改變、各家 JDK 發行版的免費支援能撐到哪一年,順便提一下 2026 年 3 月剛 GA 的非 LTS Java 26 帶來什麼亮點。
進入版本演進之前,先確認一下「LTS」是什麼,以及 Oracle JDK、OpenJDK、Eclipse Temurin、Amazon Corretto 這幾個名字到底差在哪。這部分以前寫過一篇完整介紹,沒有概念的可以先看 OracleJDK、OpenJDK 之外的 Java JDK JRE JVM 環境選擇 ,下面就直接把重點當前提:免費長期支援要選 Eclipse Temurin、Amazon Corretto、Azul Zulu 這類社群 / 第三方發行版,Oracle JDK 雖然從 17 開始有 NFTC 免費授權,但只到下一版 LTS 釋出後一年,並不適合長期生產環境用。
為什麼要關心 LTS
Java 從 9 開始改成每六個月一個版本(正式叫 feature release),但短週期版本只有六個月安全更新,下一版出來舊的就停止維護。對個人玩具專案無所謂,對企業生產環境就吃不消,所以 Oracle 在 2018 年宣佈 LTS(Long-Term Support)策略,挑某幾個版本給長達數年的安全更新,OpenJDK 社群與主流發行版都跟進。LTS 等於是企業選版本的標準答案。
LTS 釋出節奏一開始是三年一版(8 → 11 → 17 → 21),不過從 21 之後縮短為 兩年一版(21 → 25),下一版 LTS 27 預計 2027 年 9 月。節奏縮短的背後其實是業界壓力:virtual threads、pattern matching 這些新功能太重要,preview 週期拖三年才轉正太慢,乾脆把 LTS 加速。
五個 LTS 的釋出與支援時間整理如下,特別把 Oracle、Eclipse Temurin、Amazon Corretto 三家分開列,因為它們的免費期差距很大:
| LTS | GA 時間 | Oracle Premier | Oracle 延伸 | Eclipse Temurin | Amazon Corretto |
|---|---|---|---|---|---|
| 8 | 2014-03 | 2022-03(已結束) | 2030-12 | 2030-12 | 2030-12 |
| 11 | 2018-09 | 2023-09(已結束) | 2032-01 | 2027-10 | 2032-01 |
| 17 | 2021-09 | 2026-09 | 2029-09 | 2027-10 | 2029-10 |
| 21 | 2023-09 | 2028-09 | 2031-09 | 2029-12 | 2030-10 |
| 25 | 2025-09-16 | 2030-09 | 2033-09 | 2031-09 | 2032-10 |
重點提醒:Oracle JDK 17 / 21 / 25 雖然在 NFTC 授權下可以免費商用,但這個免費期只持續到「下一個 LTS GA 之後約一年」。例如 Java 21 的 NFTC 免費期會在 2026-09 結束,之後想用 Oracle JDK 就得買 Oracle Java SE Subscription。Corretto、Temurin 等 OpenJDK 發行版整段都免費,差別只在維護長度。
Java 8 — 一切的起點
Java 8 是現代 Java 的分水嶺。2014 年發佈,到 2026 年的今天還是市佔率最高的版本,原因不只是企業升級慢,也是因為它一次帶來的功能實在太多:
- Lambda 表達式:把過去一坨 anonymous inner class 折成一行
- Stream API:宣告式的集合運算,可串接、可平行化
- java.time 套件:取代難用的
Date、Calendar,詳細介紹寫過 Java 8 的日期時間 API 介紹與各種常見操作範例 - Optional:讓「可能沒有值」這件事被型別系統表達出來
- interface default methods:介面可以帶實作,後續才可能進化 Stream API
下面這段是最經典的 Lambda + Stream 範例,從 Java 8 開始到 25 都可以這樣寫:
// 從一串名字裡找出長度大於 3 的,全部轉大寫,排序後印出
List<String> names = List.of("ada", "kyle", "tom", "alice");
names.stream()
.filter(n -> n.length() > 3) // Lambda
.map(String::toUpperCase) // method reference
.sorted()
.forEach(System.out::println); // ALICE, KYLE
Java 8 為什麼黏住這麼久?除了功能本身夠用,企業系統的相依鏈、Spring 4 / 5 的長尾、Android 一度只支援部分 Java 8 功能,都讓升級動機被稀釋。Oracle Premier Support 雖然在 2022-03 結束,但 Eclipse Temurin、Amazon Corretto 還會免費維護到 2030-12,所以舊系統要繼續吃 Java 8 安全更新,技術上沒問題。
Java 11 — 吸收 9、10 的整理期
Java 11 是 Java 8 之後第一個 LTS,等於把 9、10 兩個短週期版本累積的功能一次給長期維護。
Java 11 自身的重點
- JEP 321 標準化 HTTP Client:之前在 incubator 階段,11 終於進入
java.net.http正式套件,支援 HTTP/2 與 async - 移除 Java EE 與 CORBA 模組(這些 API 已過時)
- ZGC 實驗性首次登場
- 單檔 launch:
java HelloWorld.java不用先編譯就能跑,寫 script 方便很多 - TLS 1.3
吸收 Java 9(2017-09)
- JEP 261 模組系統(Project Jigsaw):JDK 本身被切成模組,大型應用也能用
module-info.java宣告依賴 - JShell:官方 REPL,學習與測試 API 很方便
- List.of()、Map.of() 等 immutable factory:跟以前
Arrays.asList()的差別寫過 Java 的 Arrays.asList() 與 List.of() 差別 - G1 設為預設 GC
吸收 Java 10(2018-03)
- JEP 286 var 區域變數型別推斷:寫起來像
var list = new ArrayList<String>();,少打幾個字 - G1 並行 full GC
不過 Java 11 的吸收成績只能算半成功。模組系統雖然強大,業界吸收速度卻很慢,許多框架(Spring、Hibernate)為了向下相容並沒有完全模組化,結果開發者升上 11 之後常常被 reflection、JDK 內部 API 的存取限制咬到。Oracle Premier Support 已在 2023-09 結束,但 Corretto 免費維護到 2032-01,繼續用 Java 11 還是夠安全。
Java 17 — 吸收 12-16,現代 Java 成型
Java 17 是「現代 Java」的雛形成型版本,把 12 到 16 累積的 preview 功能大量轉正。
Java 17 自身的重點
- JEP 409 sealed classes:限制誰可以繼承一個 class,配合 pattern matching 是 ADT(algebraic data type)的基礎。詳細寫過 Java 17 新增的 sealed、non-sealed class 與 final class 差別
- JEP 403 強封裝 JDK 內部 API:
sun.*、com.sun.*之類的內部 API 預設禁止反射存取,這個改動讓很多舊 library 升級時直接爆炸 - Enhanced Pseudo-Random Number Generators
- 新 macOS 渲染 pipeline(Apple Silicon 友善)
吸收 Java 12-16 的關鍵正式功能
- 14:JEP 361 switch expressions 正式,switch 終於可以當運算式用、可以 yield 值。switch 的整段演進另外寫過 從 Java 7、17、21、25 到 Java 26,Java Switch 關鍵字的演變 。同版還加入 helpful NullPointerExceptions(NPE 訊息會直接告訴是哪個變數 null)
- 15:text blocks 正式,三引號多行字串;ZGC、Shenandoah 都從實驗轉正式
- 16:JEP 395 records 正式,一行宣告 immutable data class,跟 Lombok 的取捨寫過 Java 16 新增的 record 教學,與 lombok 和 POJO 的比較 ;同版還有 JEP 394 pattern matching for instanceof 正式、Unix-domain sockets
到 Java 17,現代 Java 的字典裡多了 sealed、record、pattern matching、text blocks、switch expression,整個語法樣貌跟 Java 8 已經是兩個世代的東西。底下這段示範 switch expression 的寫法:
// switch 當運算式用,可以直接 return 結果
String role = switch (level) {
case 1, 2 -> "junior"; // 多 case 合併
case 3, 4, 5 -> "mid";
case 6, 7 -> "senior";
default -> throw new IllegalArgumentException("unknown level: " + level);
};
另外 Java 15 正式的 text blocks 也是 17 帶進主流的關鍵語法,寫 SQL、JSON、HTML 終於不用一堆字串拼接:
// 三引號開頭,內部排版照原樣保留,縮排會自動以最少縮排為基準對齊
String json = """
{
"name": "kyle",
"role": "engineer",
"skills": ["Java", "Spring", "Linux"]
}
""";
// 寫 SQL 也乾淨多了
String sql = """
SELECT id, name, created_at
FROM users
WHERE status = 'active'
AND created_at > ?
ORDER BY created_at DESC
""";
支援狀態:Oracle Premier 到 2026-09,Eclipse Temurin 到 2027-10,Corretto 到 2029-10。
Java 21 — 吸收 18-20,virtual threads 元年
Java 21 是這幾年最重磅的一版,整整 15 個 JEP,其中最值得記住的是 virtual threads 終於從 preview 走到正式。
Java 21 自身的重點
- JEP 444 virtual threads 正式:對高併發 IO 服務(HTTP backend、資料庫互動)是劃時代改變,過去要靠 reactive programming 才能擠出的吞吐量,現在用同步寫法就達得到
- JEP 431 sequenced collections:替 List、Deque、LinkedHashSet 等補上統一的
getFirst()、getLast()、reversed()介面 - JEP 441 pattern matching for switch 正式:switch 可以對型別、record 結構做匹配
- JEP 440 record patterns 正式:可以直接拆解 record 的欄位
- generational ZGC:ZGC 加上世代分區,提升吞吐
- KEM API:為後量子加密鋪路
吸收 Java 18-20
- 18:JEP 400 預設字元集改為 UTF-8。這是個容易被忽略卻影響甚大的改動,過去
new FileWriter("a.txt")在不同平台、不同 locale 會用不同編碼,從 18 開始終於統一;同版還有簡易 web server(jwebserver) - 19:virtual threads 第一輪 preview、structured concurrency 進孵化
- 20:scoped values 進孵化、virtual threads 第二輪 preview
底下示範 virtual threads,跟一般 thread 寫法幾乎一樣,但可以開到幾百萬個都不會把記憶體吃光:
// 用 virtual thread executor,跑一萬個並發 IO 任務
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
// 模擬 IO,例如打 HTTP 或讀資料庫
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor 自動 close,等所有任務完成
這段如果換成傳統 platform thread,10000 個 thread 會直接把 JVM 壓垮;換成 virtual thread 之後,每個任務的 stack 只用幾 KB,整個程式輕鬆跑完。對寫慣 reactive 的人來說,這幾乎是「終於可以用同步寫法了」的解放。
JEP 441 把 pattern matching 帶進 switch,配合 sealed class 與 record 就能寫出真正的 ADT 風格判斷,再也不用層層 if-else 加 instanceof 強制轉型:
// 一個密封繼承樹(sealed),所有 Shape 子類都列舉出來
sealed interface Shape permits Circle, Square, Triangle {}
record Circle(double radius) implements Shape {}
record Square(double side) implements Shape {}
record Triangle(double base, double height) implements Shape {}
// switch 直接對型別匹配,編譯器會檢查是否窮舉所有 case
double area = switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Square s -> s.side() * s.side();
case Triangle t -> 0.5 * t.base() * t.height();
// 不需要 default:sealed + 全部窮舉,編譯器幫忙保證
};
JEP 440 record patterns 更進一步,把 record 的欄位直接拆解出來,省掉一大堆 getter 呼叫:
record Point(int x, int y) {}
record Line(Point from, Point to) {}
// 直接在 switch case 裡解構 record,連嵌套的 record 也能拆
String describe = switch (obj) {
case Point(int x, int y) -> "點 (" + x + "," + y + ")";
case Line(Point(var x1, var y1),
Point(var x2, var y2)) -> "線段 " + x1 + "," + y1 + " → " + x2 + "," + y2;
case null -> "空值";
default -> "未知形狀";
};
Java 21 也是 LTS 節奏改變的起點,從 21 開始下一版 LTS 不再是三年後(24)而是兩年後(25)。支援狀態:Oracle Premier 到 2028-09,Temurin 到 2029-12。
Java 25 — 吸收 22-24,目前最新 LTS
Java 25 在 2025 年 9 月 GA,是寫這篇文章時最新的 LTS。共 18 個 JEP,重點是把 21 之後兩年累積的功能轉正、補完幾個老問題。
Java 25 自身的重點
- JEP 512 compact source files & instance main:寫
void main()就能執行,不用public static void main(String[] args)那一坨樣板。給新手教學跟一次性 script 用 - JEP 513 flexible constructor bodies:建構子可以在
super()之前做事(驗證參數、預處理),不再受限於必須第一行就呼叫父類別建構子 - JEP 519 compact object headers:物件 header 從 96-128 bit 壓到 64 bit,整個 heap 省記憶體,對大型 application 是免費效能升級
- JEP 510 KDF API、JEP 509 JFR CPU-time profiling
- module import declarations、PEM API、generational Shenandoah 正式
- 移除 32-bit x86 支援
吸收 Java 22-24
- 22:JEP 454 FFM API 正式(Foreign Function & Memory,取代 JNI 的現代外部函數呼叫)、unnamed patterns 正式、stream gatherers 進 preview、多檔 source launch
- 23:ZGC 預設改為 generational、Markdown Javadoc
- 24:JEP 485 stream gatherers 正式(Stream API 自 Java 8 之後最大擴充,可以自訂中間操作)、JEP 484 Class-File API 正式、JEP 483 AOT class loading、永久關閉 Security Manager、ML-KEM / ML-DSA 後量子加密、JEP 491 virtual thread synchronization without pinning(補上 21 virtual thread 在
synchronized區塊內會 pin 住底層 carrier thread 的最大坑)
下面是 Java 25 的 instance main 寫法,以及 Java 24 開始正式的 stream gatherers 範例:
// JEP 512 compact source files:整個檔案就這四行,存成 Hello.java
// 不需要宣告 class、不需要 public static void main、不需要 import
void main() {
println("Hello from Java 25"); // println 直接可用,等同 System.out.println
}
// 也可以收命令列參數,沒用到就不必宣告
void main(String[] args) {
println("收到參數數量:" + args.length);
}
JEP 512 真正的價值不在「少打字」,而在於降低 Java 入門門檻——教學第一堂課終於不用解釋什麼是 public、什麼是 static、什麼是 String[] args,可以直接寫邏輯。對寫一次性 script 的人也很方便,java Hello.java 直接跑。
另一個值得試的是 Java 24 起正式的 stream gatherers,這是 Stream API 自 Java 8 之後最大擴充,可以自訂中間操作(之前只能組合內建的 filter/map/flatMap 等):
import static java.util.stream.Gatherers.windowSliding;
import static java.util.stream.Gatherers.windowFixed;
// 滑動視窗:每次取連續 N 個元素,視窗每次往後移一格
var pairs = Stream.of(1, 2, 3, 4, 5)
.gather(windowSliding(2))
.toList();
// [[1,2], [2,3], [3,4], [4,5]]
// 固定視窗:分塊不重疊,常用於 batch 處理
var batches = Stream.of(1, 2, 3, 4, 5, 6, 7)
.gather(windowFixed(3))
.toList();
// [[1,2,3], [4,5,6], [7]]
從 21 到 25 的兩年,Java 把 virtual threads 補完(不再 pin)、Stream 擴充(gatherers)、heap 壓縮(compact headers),整條「現代化、高性能 Java」的線就此完整。支援狀態:Oracle Premier 到 2030-09,Temurin 到 2031-09,Corretto 到 2032-10。
番外:Java 26 — 非 LTS 但目前最新
Java 26 在 2026 年 3 月 17 日 GA,雖然不是 LTS(只有六個月安全更新),但是寫這篇文章的當下最新版本,幾個亮點值得記著,下一版 LTS 27 大概會把這些轉正:
- JEP 517 HTTP/3 for HTTP Client(正式):Java 11 標準化的 HTTP Client 終於支援 HTTP/3 與 QUIC,網路 stack 跟上現代瀏覽器
- JEP 516 AOT object caching with any GC(正式):Project Leyden 的成果延伸,啟動速度持續優化
- JEP 522 G1 GC throughput improvement(正式):減少 G1 同步開銷,對既有用 G1 的服務是免費效能升級
- JEP 504 移除 Applet API(正式):
java.applet終於進墳墓 - JEP 500 Prepare to Make Final Mean Final:收緊 reflection 修改 final 欄位的漏洞,是後續真正鎖死 final 的鋪路
- JEP 525 Structured Concurrency 第 6 輪 preview:從 21 開始 preview 至今還沒轉正,是 Loom 後續最重要的併發 API
- JEP 530 Primitive types in patterns 第 4 輪 preview
- JEP 529 Vector API 第 11 輪 incubator:仍在孵化
Java 26 沒有戲劇性的新功能,主要是把 25 沒收完的 preview 繼續推進,加上 HTTP/3、G1 同步優化等實用補完。生產環境繼續用 25 LTS 是最保險的選擇,不過 HTTP/3 client 是值得單獨拿來玩的東西。
該升級嗎?該升到哪一版?
還停在 Java 8 的場景其實非常多——金融系統、舊 Spring 服務、Android 老專案、JVM 上的 Scala 2 / Kotlin 1 應用,這些不見得要立刻動。Java 8 在 Eclipse Temurin、Amazon Corretto 上還會免費維護到 2030-12,安全更新有保障。但如果業務上開始想要 virtual threads、record、pattern matching 這些東西,那就值得排升級時程。
想升級的話有個原則:不要中途停在 11 或 17,直接跳 21 或 25。原因是升版的成本主要在「處理 reflection 與內部 API 被擋住、相依套件升版、CI 流程更新」這些雜事上,做一次跟做兩次差不多。既然要動,就一步到位。
- 跳 Java 21:穩定性已經夠成熟(GA 兩年多),virtual threads 對 IO 密集服務直接受益,Spring Boot 3 完美支援
- 跳 Java 25:Java 21 的 virtual thread pin 問題已修(JEP 491)、stream gatherers 對資料處理寫法更乾淨、compact object headers 省記憶體。新專案直接 25
框架兼容性也是考量點:Spring Boot 3 要求 Java 17+、Spring Boot 4 預計要求 21+,所以未來 12 個月內想升 Spring Boot 4 的服務,最低就要規劃 21。
常見 QA
Q1:LTS 是誰定的?非 LTS 的版本能用嗎?
LTS 是 Oracle 在 2018 年宣佈的策略,OpenJDK 社群與主流發行版(Temurin、Corretto、Zulu)跟進。非 LTS 版本(例如 22、23、24、26)只有六個月安全更新,適合愛嘗鮮、生命週期短的專案,不適合長期維護的服務。但拿來開發、實驗、寫 demo 完全沒問題。
Q2:用免費的 OpenJDK 跟 Oracle JDK 有什麼差別?
功能上幾乎一樣(Oracle JDK 跟 OpenJDK 共用同一份原始碼基底)。差別主要在授權與支援時長,詳細比較可以看 OracleJDK、OpenJDK 之外的 Java JDK JRE JVM 環境選擇 。重點是:免費長期支援要選 Temurin、Corretto 或 Zulu,不要用 Oracle JDK 跑生產環境(除非有買 Oracle Java SE Subscription)。
Q3:升級會踩什麼坑?
- Java 8 → 11:模組系統(JPMS)讓很多 reflection、JDK 內部 API 被擋住,舊 library 直接壞
- Java 11 → 17:JEP 403 強封裝 JDK 內部 API,更多反射程式爆炸;要記得加
--add-opens或升級到對 17 友善的 library 版本 - Java 17 → 21:相對平順,只要原本沒亂用 deprecated API
- Java 21 → 25:注意 32-bit x86 支援移除、Security Manager 永久關閉、移除幾個冷門 API
Q4:virtual threads 是不是 Java 21 推出來的?
對。但前身在 Java 19 開始 preview,21 才正式。Java 25 進一步補完(JEP 491 解決 synchronized 區塊內 pin 住 carrier thread 的問題)。如果寫 IO 密集服務(HTTP 後端、資料庫互動),virtual threads 是這幾年最有感的升級理由。
Q5:Java 21 跟 25 該選哪個?
新專案直接 25。既有專案如果 21 跑得穩,可以等個半年到一年看 25 的 patch 釋出穩定後再升。25 的免費維護期更長(Corretto 到 2032-10),長期看比 21 划算。
Q6:JDK 內建的 HTTP Client 真的能取代 OkHttp、Apache HttpClient 嗎?
Java 11 標準化的 HTTP Client(JEP 321)支援 HTTP/2、async、reactive,到 Java 26 還補上 HTTP/3,日常 REST 呼叫絕對夠用。但生態系成熟度(攔截器、metrics、retry policy、認證套件)目前還是 OkHttp、Apache 領先,做複雜整合時可能還是會回去用第三方。
Q7:LTS 改為 2 年是好是壞?
對開發者個人來說是好事——virtual threads 從 19 preview 到 21 正式只花兩年,新功能更快進到 LTS,框架與生態系也會跟著加速。對企業則是壓力——升版節奏吃緊,預算與測試人力得跟上。整體來說 LTS 加速是 Java 跟上 Go、Rust、Kotlin 那種快節奏語言的必要動作。
小結
整理三個重點作收:
- Java 8 到 25 這 11 年,語言層面從以 OOP 為主,進化成「OOP + Functional + Pattern Matching + 新 Concurrency 模型」的完整體系,現代 Java 的字典已經跟 Java 8 是兩個世代
- LTS 是企業選版本的安全網,但要記得 Oracle JDK 跟 OpenJDK 發行版的免費支援時長差很多。長期生產環境就用 Eclipse Temurin、Amazon Corretto、Azul Zulu
- 還在 Java 8 / 11 的服務想升級,建議直接跳 21 或 25,跳 17 在現在已經不划算。新專案沒包袱的話就用 25
從高中寫 Java 6 / 7 的 anonymous inner class 到現在用 Java 25 的 virtual thread + record pattern,這條時間線確實看得到語言的活力。Java 從來不是寫起來最帥的語言,但它的演進方向一直很實用,把開發者真正會踩的痛點一個一個處理掉。下一版 LTS 27 預計 2027 年 9 月,到時候大概會是 structured concurrency、primitive patterns、字串模板(template)等 preview 轉正的時刻,繼續期待。
參考資料: