概述
Java 24 于 2025 年 3 月發(fā)布,該版本提供24項(xiàng)新特性(含10項(xiàng)孵化/預(yù)覽/實(shí)驗(yàn)功能)
JEP 404: 分代 Shenandoah(實(shí)驗(yàn)性)
::: info JEP 404: Generational Shenandoah (Experimental)
Enhance the Shenandoah garbage collector with experimental generational collection capabilities to improve sustainable throughput, load-spike resilience, and memory utilization.
:::
通過(guò)實(shí)驗(yàn)性分代收集功能增強(qiáng) Shenandoah 垃圾回收器,以提高可持續(xù)吞吐量、負(fù)載峰值彈性和內(nèi)存利用率。
核心目標(biāo)
在保持Shenandoah原有的低暫停時(shí)間優(yōu)勢(shì)基礎(chǔ)上,進(jìn)一步減少內(nèi)存占用和CPU開(kāi)銷。
工作原理
將堆內(nèi)存劃分為年輕代和老年代,優(yōu)先且更頻繁地收集年輕代(通常包含大量短生命周期對(duì)象),避免其過(guò)早晉升到老年代,減少全局垃圾回收的需要。
- 新生代專用回收策略:采用復(fù)制篡法快速回收短生命周期對(duì)象,減少老年代掃描頻率
- 卡表 (Card Table) 優(yōu)化:精確記錄老年代到新生代的跨代引用,降低 GC 停頓時(shí)間 30 %以上
- 井行標(biāo)記增強(qiáng):在并發(fā)標(biāo)記階段優(yōu)先處理新生代區(qū)域,使平均 GC 暫停時(shí)間控制在 2ms 以內(nèi)。實(shí)測(cè)表明,在 16GB 堆內(nèi)存的微服務(wù)場(chǎng)景下,分代 Shenandoah 相比原版吞吐量提升 40 %,同時(shí)保持亞毫秒級(jí)的最大暫停時(shí)間,成為低延遲應(yīng)用的理想選擇。
啟用方式
需添加JVM參數(shù):
-XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational
適用場(chǎng)景
- 低延遲高響應(yīng)應(yīng)用:例如實(shí)時(shí)交易系統(tǒng)、交互式數(shù)據(jù)分析平臺(tái)。
- 大量短生命周期對(duì)象:例如處理大量臨時(shí)請(qǐng)求或緩存數(shù)據(jù)的應(yīng)用。
- 關(guān)注內(nèi)存效率:希望降低垃圾收集器內(nèi)存開(kāi)銷和CPU使用率的應(yīng)用。
::: info
- Shenandoah GC最初在JDK 12中作為實(shí)驗(yàn)性功能引入,其最大特點(diǎn)是通過(guò)與應(yīng)用程序線程并發(fā)執(zhí)行大部分工作來(lái)盡可能減少GC暫停時(shí)間,且暫停時(shí)間與堆大小無(wú)關(guān)。
- 后在JDK 15中,Shenandoah GC從實(shí)驗(yàn)性功能轉(zhuǎn)為正式的生產(chǎn)功能,不再需要額外的解鎖實(shí)驗(yàn)參數(shù),但其默認(rèn)的垃圾收集器仍然是G1。
- 分代Shenandoah旨在與G1、ZGC(JEP 439已為ZGC引入分代模式)等現(xiàn)代收集器同步發(fā)展,同時(shí)保持自身在最小化延遲方面的獨(dú)特優(yōu)勢(shì)。
:::
JEP 450: 緊湊對(duì)象頭(實(shí)驗(yàn)性)
::: info JEP 450: Compact Object Headers (Experimental)
Reduce the size of object headers in the HotSpot JVM from between 96 and 128 bits down to 64 bits on 64-bit architectures. This will reduce heap size, improve deployment density, and increase data locality.
:::
重構(gòu)了Java對(duì)象的內(nèi)存布局,將 HotSpot JVM 中的普通對(duì)象頭大小從96到128位減少到64位,從而提升內(nèi)存利用率和應(yīng)用性能。
核心原理
Java 對(duì)象在堆中的存儲(chǔ)包含對(duì)象頭和實(shí)例數(shù)據(jù)。對(duì)象頭又分為:
- 標(biāo)記字 (Mark Word):存儲(chǔ)哈希碼、GC 年齡、鎖狀態(tài)、線程持有的鎖、偏向線程ID、偏向時(shí)間戳等運(yùn)行時(shí)數(shù)據(jù)。
- 類指針 (Class Pointer):指向?qū)ο蟮念愒獢?shù)據(jù)。
- 數(shù)組長(zhǎng)度:數(shù)組對(duì)象的頭部還會(huì)額外包含該字段。
在 64 位 JVM 中,普通對(duì)象頭通常占 12字節(jié)(96位) 至 16字節(jié)(128位)。對(duì)于許多平均大小僅為 32-64 字節(jié)的小對(duì)象來(lái)說(shuō),對(duì)象頭的開(kāi)銷占比非常高,可能達(dá)到 20% 到 50%。JEP 450 通過(guò)以下方式將對(duì)象頭壓縮至 64 位 (8 字節(jié)):
- 壓縮類指針:將原本 32 位的壓縮類指針進(jìn)一步優(yōu)化為 22 位,并將其編碼嵌入標(biāo)記字中。
- 標(biāo)記字的功能重組與升級(jí):對(duì)固定的 64 位標(biāo)記字空間進(jìn)行了徹底的重新規(guī)劃,將其劃分為一個(gè)精細(xì)的功能位域集合,以同時(shí)承載原有和新增的信息
- 鎖機(jī)制革新:傳統(tǒng)的偏向鎖 和輕量級(jí)鎖 會(huì)覆蓋整個(gè)標(biāo)記字(除鎖標(biāo)記位外),與緊湊對(duì)象頭中必須保留類指針的設(shè)計(jì)沖突。因此,緊湊對(duì)象頭不再支持偏向鎖和棧鎖。它依賴 JDK 22 中引入的對(duì)象監(jiān)視表 來(lái)管理重量級(jí)鎖信息。
新舊對(duì)象頭布局對(duì)比
為了更直觀地理解其變化,可以參考下表對(duì)傳統(tǒng)對(duì)象頭與緊湊對(duì)象頭進(jìn)行的對(duì)比:
Java傳統(tǒng)對(duì)象頭
傳統(tǒng)對(duì)象頭大小
| 是否壓縮 | 對(duì)象類型 | 大小 | 說(shuō)明 |
|---|---|---|---|
| 壓縮 | 普通對(duì)象 | 12字節(jié)(96位) | 標(biāo)記字8B(64位)+ 類指針4B(32位) |
| 壓縮 | 數(shù)組對(duì)象 | 16字節(jié)(128位) | 標(biāo)記字8B(64位)+ 類指針4B(32位)+ 數(shù)組長(zhǎng)度4B(32位) |
| 未壓縮 | 普通對(duì)象 | 16字節(jié)(128位) | 標(biāo)記字8B(64位)+ 類指針8B(64位) |
| 未壓縮 | 數(shù)組對(duì)象 | 20字節(jié)(160位) | 標(biāo)記字8B(64位)+ 類指針8B(64位)+ 數(shù)組長(zhǎng)度4B(32位) |
傳統(tǒng)對(duì)象頭標(biāo)記字(Mark Word)
<table>
<thead>
<tr>
<th>狀態(tài)</th>
<th>鎖狀態(tài)</th>
<th>偏向鎖</th>
<th>GC分代
年齡</th>
<th>未使用</th>
<th>其他</th>
</tr>
</thead>
<tbody>
<tr>
<td>無(wú)鎖狀態(tài)</td>
<td>01</td>
<td>0</td>
<td>4位</td>
<td>1位</td>
<td>哈希碼(31位)+ 未使用(25位)</td>
</tr>
<tr>
<td>偏向鎖狀態(tài)</td>
<td>01</td>
<td>1</td>
<td>4位</td>
<td>1位</td>
<td>線程ID(54位)+ epoch(2位)</td>
</tr>
<tr>
<td>輕量級(jí)鎖狀態(tài)</td>
<td>00</td>
<td colspan="4">指向鎖記錄的指針(62位)</td>
</tr>
<tr>
<td>重量級(jí)鎖狀態(tài)</td>
<td>10</td>
<td colspan="4">指向Monitor的指針(62位)</td>
</tr>
<tr>
<td>GC 分代年齡</td>
<td>11</td>
<td colspan="4">GC所需標(biāo)記信息</td>
</tr>
</tbody>
</table>
緊湊對(duì)象頭
| 標(biāo)記位 | 自轉(zhuǎn)發(fā)標(biāo)記位 | GC分代年齡 | 預(yù)留 | 哈希碼 | 壓縮類指針 |
|---|---|---|---|---|---|
| 2位 | 1位 | 4位 | 4位 | 31位 | 22位 |
啟用方式
Java 24 中,緊湊對(duì)象頭是實(shí)驗(yàn)性功能,需要特定 JVM 參數(shù)啟用,Java 25 成為正式功能,無(wú)需手動(dòng)啟動(dòng)。
-XX:+UnlockExperimentalVMOptions -XX:+UseCompactObjectHeaders
適用場(chǎng)景
緊湊對(duì)象頭尤其適用于以下場(chǎng)景:
- 大量小對(duì)象的應(yīng)用(如微服務(wù)、DTO、緩存元素)。
- 內(nèi)存敏感型工作負(fù)載(希望降低內(nèi)存占用和提高部署密度)。
- 關(guān)注緩存效率和高吞吐量的應(yīng)用。
在決定是否啟用時(shí),需考慮:
- 應(yīng)用程序特性:若應(yīng)用嚴(yán)重依賴偏向鎖,需評(píng)估其影響。
- GC 選擇:目前該特性主要支持 G1 和 Parallel GC。對(duì)于 ZGC 的支持尚未完成。
- 類加載數(shù)量:確保應(yīng)用加載的類數(shù)量遠(yuǎn)低于 400 萬(wàn)的上限。
JEP 472: 準(zhǔn)備限制 JNI 的使用
::: info JEP 472: Prepare to Restrict the Use of JNI
Issue warnings about uses of the Java Native Interface (JNI) and adjust the Foreign Function & Memory (FFM) API to issue warnings in a consistent manner. All such warnings aim to prepare developers for a future release that ensures integrity by default by uniformly restricting JNI and the FFM API. Application developers can avoid both current warnings and future restrictions by selectively enabling these interfaces where essential.
:::
JEP 472(Prepare to Restrict the Use of JNI)是JDK 24中的一個(gè)重要提案,旨在增強(qiáng)Java平臺(tái)的安全性,通過(guò)引入對(duì)Java本地接口(JNI)使用的限制和警告,為未來(lái)版本默認(rèn)禁止通過(guò)JNI或FFM API與本地代碼互操作做準(zhǔn)備。
核心目標(biāo)
JEP 472的主要目標(biāo)包括:
- 保持JNI地位:繼續(xù)保持JNI作為與本地代碼互操作的標(biāo)準(zhǔn)方式的地位。
- 準(zhǔn)備生態(tài)系統(tǒng):準(zhǔn)備Java生態(tài)系統(tǒng)迎接未來(lái)的版本,默認(rèn)不允許通過(guò)JNI或FFM API與本地代碼互操作。自該版本起,應(yīng)用程序開(kāi)發(fā)者必須在啟動(dòng)時(shí)顯式啟用JNI和FFM API的使用。
- 統(tǒng)一使用方式:統(tǒng)一JNI和FFM API的使用方式,使庫(kù)維護(hù)者可以在兩者之間遷移而無(wú)需應(yīng)用程序開(kāi)發(fā)者更改任何命令行選項(xiàng)。
動(dòng)機(jī)與背景
JNI自JDK 1.1引入以來(lái),一直是Java代碼與本地代碼(通常用C/C++編寫(xiě))互操作的主要手段。但它也帶來(lái)了顯著的安全風(fēng)險(xiǎn):
- 未定義行為與崩潰:調(diào)用本地代碼可能導(dǎo)致任意的未定義行為,包括JVM崩潰,且Java運(yùn)行時(shí)無(wú)法阻止此類問(wèn)題,也無(wú)法拋出可捕獲的異常。
- 內(nèi)存安全風(fēng)險(xiǎn):本地代碼和Java代碼經(jīng)常通過(guò)直接字節(jié)緩沖區(qū)交換數(shù)據(jù),這些區(qū)域不受JVM垃圾收集器管理。本地代碼可能生成由無(wú)效內(nèi)存區(qū)域支持的字節(jié)緩沖區(qū),在Java代碼中使用會(huì)引發(fā)未定義行為。
- 繞過(guò)訪問(wèn)檢查:本地代碼可以使用JNI訪問(wèn)字段和調(diào)用方法,而不經(jīng)過(guò)JVM的任何訪問(wèn)檢查,甚至可以改變
final字段的值,從而破壞其他Java代碼的一致性。 - 不良GC行為:不正確使用某些JNI函數(shù)(如
GetPrimitiveArrayCritical和GetStringCritical)可能導(dǎo)致不良的垃圾回收行為。
JDK 22引入的外部函數(shù)與內(nèi)存(FFM)API作為JNI的現(xiàn)代替代方案,雖然也面臨類似風(fēng)險(xiǎn),但其設(shè)計(jì)通過(guò)“受限方法”和要求開(kāi)發(fā)者顯式選擇加入來(lái)緩解風(fēng)險(xiǎn)。JEP 472旨在使JNI遵循類似的安全范式,這是確保Java平臺(tái)默認(rèn)一致性(默認(rèn)安全)的長(zhǎng)期努力的一部分,其他相關(guān)舉措包括移除sun.misc.Unsafe中的內(nèi)存訪問(wèn)方法(JEP 471)和限制動(dòng)態(tài)加載代理(JEP 451)。
核心變化
JEP 472的核心變化在于對(duì)JNI的“加載和鏈接本地庫(kù)”操作施加本地訪問(wèn)限制(Native Access Restrictions),并與FFM API保持一致。
-
受限操作:在JDK 24中,以下操作將默認(rèn)觸發(fā)警告(未來(lái)版本將拋出異常):
- 調(diào)用
System::loadLibrary,System::load,Runtime::loadLibrary或Runtime::load。 - 聲明
native方法。
- 調(diào)用
-
啟用本地訪問(wèn):應(yīng)用程序開(kāi)發(fā)者必須顯式啟用本地訪問(wèn)以避免警告和未來(lái)的異常。這可以通過(guò)以下方式實(shí)現(xiàn):
- 命令行選項(xiàng):
# 為類路徑上的所有代碼啟用 java --enable-native-access=ALL-UNNAMED -jar your_app.jar # 為模塊路徑上的特定模塊啟用 java --enable-native-access=MODULE1,MODULE2 -jar your_app.jar - 參數(shù)文件:在
config-file中寫(xiě)入--enable-native-access=ALL-UNNAMED,然后運(yùn)行java @config-file -jar myapp.jar - 環(huán)境變量傳遞:
export JDK_JAVA_OPTIONS="--enable-native-access=ALL-UNNAMED",然后運(yùn)行java -jar myapp.jar - JAR清單屬性:在可執(zhí)行JAR的清單中添加
Enable-Native-Access: ALL-UNNAMED。 - 其他方式:如通過(guò)
jlink定制運(yùn)行時(shí)鏡像時(shí)添加選項(xiàng),或使用ModuleLayer.Controller::enableNativeAccess方法(其本身是受限方法)。
- 命令行選項(xiàng):
-
控制限制效果:新的命令行選項(xiàng)
--illegal-native-access用于控制違反限制時(shí)的行為:-
warn(JDK 24默認(rèn)):允許操作但發(fā)出警告(每個(gè)模塊最多一次)。 -
deny:拋出IllegalCallerException(未來(lái)版本的默認(rèn)行為)。 -
allow:允許操作繼續(xù)(未來(lái)版本會(huì)移除)。
-
未來(lái)計(jì)劃
JEP 472是分階段實(shí)施的長(zhǎng)期計(jì)劃的一部分:
- JDK 24:默認(rèn)行為是
--illegal-native-access=warn,即發(fā)出警告。 - 未來(lái)JDK版本:默認(rèn)行為將變?yōu)?code>--illegal-native-access=deny,即拋出異常,最終實(shí)現(xiàn)默認(rèn)一致性。
重要說(shuō)明
- 不棄用JNI:JEP 472并非要棄用或移除JNI,也不是要限制本地代碼本身的行為。所有本地JNI函數(shù)仍然可供本地代碼使用。
- 影響范圍:此限制主要影響加載本地庫(kù)和鏈接native方法的Java代碼。僅調(diào)用其他模塊中聲明的
native方法的代碼本身不需要啟用本地訪問(wèn)。 - FFM API對(duì)齊:JNI和FFM API在本地訪問(wèn)限制上保持一致,簡(jiǎn)化了庫(kù)的遷移和應(yīng)用程序的配置。
總結(jié)
JEP 472是Java邁向“默認(rèn)安全” 的重要一步。它通過(guò)引入對(duì)JNI使用的限制和警告,促使開(kāi)發(fā)者更顯式地管理本地代碼訪問(wèn),從而提升應(yīng)用程序和Java平臺(tái)整體的安全性和完整性。
雖然這增加了些許配置成本,但為構(gòu)建更安全可靠的Java生態(tài)系統(tǒng)奠定了基礎(chǔ)。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),關(guān)鍵是檢查現(xiàn)有代碼并適時(shí)添加--enable-native-access標(biāo)志。
JEP 475: G1 的 Late Barrier 擴(kuò)展
::: info JEP 475: Late Barrier Expansion for G1
Simplify the implementation of the G1 garbage collector's barriers, which record information about application memory accesses, by shifting their expansion from early in the C2 JIT's compilation pipeline to later.
:::
通過(guò)將G1垃圾回收器屏障的生成時(shí)機(jī),從C2 JIT編譯前期移至后期,簡(jiǎn)化了其實(shí)現(xiàn)。這些屏障的作用是記錄有關(guān)應(yīng)用程序內(nèi)存訪問(wèn)的信息。
JEP 478: 密鑰派生函數(shù) API(預(yù)覽)
::: info JEP 478: Key Derivation Function API (Preview)
Introduce an API for Key Derivation Functions (KDFs), which are cryptographic algorithms for deriving additional keys from a secret key and other data. This is a preview API.
:::
引入一個(gè)用于密鑰派生函數(shù)的預(yù)覽版API。密鑰派生函數(shù)是一種可從密鑰及其他數(shù)據(jù)中推導(dǎo)出更多密鑰的密碼學(xué)算法。
目標(biāo):
- 使應(yīng)用程序能夠使用KDF算法,例如基于HMAC的提取-擴(kuò)展密鑰派生函數(shù)(HKDF,RFC 5869)和Argon2(RFC 9106)。
- 支持在密鑰封裝機(jī)制(KEM,JEP 452)實(shí)現(xiàn)(如ML-KEM)、高層協(xié)議(如TLS 1.3中的混合密鑰交換)以及密碼方案(如混合公鑰加密HPKE,RFC 9180)中使用KDF。
- 允許安全提供商使用Java代碼或原生代碼來(lái)實(shí)現(xiàn)KDF算法。
- 包含了HKDF的一個(gè)實(shí)現(xiàn),并引入了額外的HKDF專用API。
JEP 479: 刪除 Windows 32 位 x86 端口
::: info JEP 479: Remove the Windows 32-bit x86 Port
Remove the source code and build support for the Windows 32-bit x86 port. This port was deprecated for removal in JDK 21 with the express intent to remove it in a future release.
:::
移除針對(duì) Windows 32 位 x86 端口的源代碼和構(gòu)建支持。該端口已在 JDK 21 中被標(biāo)記為棄用并計(jì)劃移除,并明確表達(dá)了在未來(lái)的版本中將其移除的意圖。
JEP 483: 提前類加載和鏈接
::: info JEP 483: Ahead-of-Time Class Loading & Linking
Improve startup time by making the classes of an application instantly available, in a loaded and linked state, when the HotSpot Java Virtual Machine starts.Achieve this by monitoring the application during one run and storing the loaded and linked forms of all classes in a cache for use in subsequent runs. Lay a foundation for future improvements to both startup and warmup time.
:::
通過(guò)讓?xiě)?yīng)用程序的類在 HotSpot Java 虛擬機(jī)啟動(dòng)時(shí)就能立即可用(即已完成加載和鏈接),來(lái)提升啟動(dòng)速度。
其實(shí)現(xiàn)方式是:在應(yīng)用的一次運(yùn)行期間進(jìn)行監(jiān)控,并將所有類的加載和鏈接形式存儲(chǔ)在緩存中以供后續(xù)運(yùn)行使用。
這同時(shí)也為未來(lái)優(yōu)化啟動(dòng)與預(yù)熱時(shí)間打下了基礎(chǔ)。
JEP 484: 類文件 API
::: info JEP 484: Class-File API
Provide a standard API for parsing, generating, and transforming Java class files.
:::
提供了一個(gè)用于解析、生成和轉(zhuǎn)換 Java 類文件的標(biāo)準(zhǔn) API,旨在替代第三方庫(kù)(如 ASM)。
- 解析(Parsing):指的是讀取一個(gè)已編譯的
.class文件,并將其內(nèi)容(如魔數(shù)、版本號(hào)、常量池、方法、字段等)分解成程序可以理解和操作的結(jié)構(gòu)化數(shù)據(jù)模型。 - 生成(Generation):指的是從零開(kāi)始,通過(guò)編程方式動(dòng)態(tài)地創(chuàng)建出一個(gè)全新的、符合規(guī)范的
.class文件。 - 轉(zhuǎn)換(Transformation):指的是讀取一個(gè)現(xiàn)有的
.class文件,對(duì)其結(jié)構(gòu)進(jìn)行修改(例如,添加/刪除方法、修改字節(jié)碼指令、植入分析代碼等),然后輸出修改后的新類文件。 - 標(biāo)準(zhǔn) API(Standard API):這是最關(guān)鍵的一點(diǎn)。這意味著該API是Java平臺(tái)本身的一部分(例如在
java.lang.classfile包下),由OpenJDK官方維護(hù)和發(fā)布。用戶無(wú)需再引入額外的第三方JAR包。
自第二個(gè)預(yù)覽版以來(lái)的更改包括重命名枚舉值、刪除某些字段、添加方法和方法重載、重命名方法以及刪除被認(rèn)為不必要的接口和方法。
JEP 485: 流收集器
::: info JEP 485: Stream Gatherers
Enhance the Stream API to support custom intermediate operations. This will allow stream pipelines to transform data in ways that are not easily achievable with the existing built-in intermediate operations.
:::
流收集器(Stream Gatherers)能為Stream API輕松添加自定義的中間操作,實(shí)現(xiàn)更復(fù)雜的數(shù)據(jù)轉(zhuǎn)換。
JEP 486: 永久禁用安全管理器
::: info JEP 486: Permanently Disable the Security Manager
The Security Manager has not been the primary means of securing client-side Java code for many years, it has rarely been used to secure server-side code, and it is costly to maintain. We therefore deprecated it for removal in Java 17 via JEP 411 (2021). As the next step toward removing the Security Manager, we will revise the Java Platform specification so that developers cannot enable it and other Platform classes do not refer to it. This change will have no impact on the vast majority of applications, libraries, and tools. We will remove the Security Manager API in a future release.
:::
安全管理器早已不是保護(hù)客戶端Java代碼的主要手段,在服務(wù)端代碼中也鮮有應(yīng)用,且維護(hù)成本高昂。因此,該機(jī)制已于2021年通過(guò)JEP 411在Java 17中被標(biāo)記為棄用并計(jì)劃移除。作為移除工作的下一步,Java平臺(tái)規(guī)范將進(jìn)行修訂,使開(kāi)發(fā)者無(wú)法啟用該功能,并確保其他平臺(tái)類不再引用它。此項(xiàng)變更對(duì)絕大多數(shù)應(yīng)用程序、庫(kù)和工具不會(huì)產(chǎn)生任何影響。Security Manager API將在未來(lái)版本中被徹底移除。
JEP 487: 作用域值(第四次預(yù)覽)
::: info JEP 487: Scoped Values (Fourth Preview)
Introduce scoped values, which enable a method to share immutable data both with its callees within a thread, and with child threads. Scoped values are easier to reason about than thread-local variables. They also have lower space and time costs, especially when used together with virtual threads (JEP 444) and structured concurrency (JEP 480). This is a preview API.
:::
引入作用域值,使方法能夠與線程中的被調(diào)用方以及子線程共享不可變數(shù)據(jù)。作用域值比線程局部變量更容易推理。它們還具有較低的空間和時(shí)間成本,特別是當(dāng)與虛擬線程(JEP 444)和結(jié)構(gòu)化并發(fā)(JEP 505)一起使用時(shí)。
有一個(gè)變動(dòng):移除了 ScopedValue 類中的 callWhere 和 runWhere 方法,使 API 保持完全流暢的鏈?zhǔn)秸{(diào)用特性。現(xiàn)在使用一個(gè)或多個(gè)綁定作用域值的唯一方式是通過(guò) ScopedValue.Carrier.call 和 ScopedValue.Carrier.run 方法。
JEP 488: 模式、instanceof 和 switch中的原始類型(第二次預(yù)覽)
::: info JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)
Enhance pattern matching by allowing primitive types in all pattern contexts, and extend instanceof and switch to work with all primitive types. This is a preview language feature.
:::
通過(guò)允許在所有模式上下文中使用原始類型來(lái)增強(qiáng)模式匹配,并擴(kuò)展 instanceof 和 switch 以使用所有原始類型。這是一個(gè)預(yù)覽語(yǔ)言功能。
在所有模式上下文中允許原始類型模式與對(duì)應(yīng)包裝類型之間的寬松轉(zhuǎn)換,并支持對(duì)記錄組件的類型寬松匹配。核心貢獻(xiàn)是:
- 原始類型模式與應(yīng)包裝類型之間的寬松轉(zhuǎn)換
- 增強(qiáng) instanceof 和 switch 構(gòu)造以支持原始類型模式作為頂級(jí)模式:允許在模式匹配中直接使用原始類型(如
int p)來(lái)匹配包裝類(如Integer)的對(duì)象。 - 增強(qiáng)記錄模式以支持類型轉(zhuǎn)換:允許在記錄模式中使用原始類型來(lái)匹配包裝類型的記錄組件值,無(wú)需嚴(yán)格匹配包裝類型。
- 增強(qiáng) instanceof 和 switch 構(gòu)造以支持原始類型模式作為頂級(jí)模式:允許在模式匹配中直接使用原始類型(如
- 對(duì)記錄組件的類型寬松匹配:在記錄模式中使用原始類型來(lái)匹配記錄的組件值時(shí),無(wú)需嚴(yán)格匹配原始類型。這一機(jī)制支持在解構(gòu)記錄時(shí)自動(dòng)完成原始類型的加寬轉(zhuǎn)換和有條件的安全縮窄轉(zhuǎn)換,顯著提升了代碼的簡(jiǎn)潔性與靈活性。
- 安全性
- 妥善處理 null 值,原始類型模式不會(huì)匹配 null,從而避免了潛在的 NullPointerException。
- 對(duì)于記錄模式中可能造成信息丟失的縮窄轉(zhuǎn)換(如 double → int),模式匹配會(huì)在運(yùn)行時(shí)自動(dòng)檢查值的兼容性,僅在不丟失信息時(shí)完成匹配,否則返回 false,保障匹配過(guò)程的安全性與可靠性。
- 語(yǔ)法與一致性更新:引入了相應(yīng)的支配性檢查規(guī)則,在同一個(gè) switch 塊中,原始類型模式(如 int i)和其對(duì)應(yīng)的包裝類型模式(如 Integer i)不能同時(shí)存在,因?yàn)樗鼈儠?huì)互相導(dǎo)致對(duì)方不可到達(dá),無(wú)論順序如何都會(huì)編譯報(bào)錯(cuò)。記錄模式也遵循相同的類型轉(zhuǎn)換原則,進(jìn)一步強(qiáng)化了模式匹配整體的語(yǔ)言一致性和表達(dá)力。
::: tip
模式 (Pattern)是一個(gè)通用概念,指的是在條件判斷中同時(shí)進(jìn)行類型檢查和變量綁定的操作。例如:obj instanceof String s 就是一個(gè)類型模式,它同時(shí)檢查 obj 是否是 String 類型,如果是,則將其綁定到變量 s。
instanceof 運(yùn)算符是應(yīng)用類型模式的第一個(gè)地方。從 Java 16 開(kāi)始,instanceof 后面可以直接跟一個(gè)類型模式和變量名。
switch 表達(dá)式/語(yǔ)句是應(yīng)用多種模式(包括類型模式、常量模式等)的更強(qiáng)大場(chǎng)所。在 Java 17 和 21 中,switch 的能力被大幅增強(qiáng),case 標(biāo)簽可以支持模式。
所以三者關(guān)系是:模式匹配是一個(gè)范式;instanceof 和 switch 是應(yīng)用該范式的語(yǔ)法工具。
因此,對(duì)JEP 488最準(zhǔn)確的理解是:為模式、instanceof 和 switch 添加對(duì)原始類型的支持。
:::
::: tip
自動(dòng)加寬轉(zhuǎn)換:
使用一個(gè)“較寬”的類型模式 (double) 去匹配一個(gè)“較窄”的組件類型 (int) 的值。編譯器允許這種操作,并自動(dòng)完成安全的值轉(zhuǎn)換。
有條件的安全縮窄轉(zhuǎn)換:
縮窄轉(zhuǎn)換是一種可能丟失信息的轉(zhuǎn)換(例如,將 double 3.14 轉(zhuǎn)換為 int 3 會(huì)丟失小數(shù)部分),因此不是無(wú)條件進(jìn)行的。
- JVM 會(huì)先檢查這個(gè) double 值是否能完全精確地轉(zhuǎn)換為一個(gè) int 值(即沒(méi)有小數(shù)部分,且在 int 的取值范圍內(nèi))
- 如果檢查通過(guò):模式匹配成功,變量被賦值
- 如果檢查不通過(guò)(值太大或有小數(shù)):模式匹配直接返回 false,不會(huì)賦值,也不會(huì)拋出異常
注意:
- “自動(dòng)加寬轉(zhuǎn)換”和“有條件的安全縮窄轉(zhuǎn)換”要求初始類型和目標(biāo)類型都是原始類型。
:::
JEP 489: 向量 API(第九個(gè)孵化器)
::: info JEP 489: Vector API (Ninth Incubator)
Introduce an API to express vector computations that reliably compile at runtime to optimal vector instructions on supported CPU architectures, thus achieving performance superior to equivalent scalar computations.
:::
引入一個(gè) API 來(lái)表達(dá)矢量計(jì)算,這些計(jì)算在運(yùn)行時(shí)可靠地編譯為受支持的 CPU 上的最佳矢量指令,從而實(shí)現(xiàn)優(yōu)于等效標(biāo)量計(jì)算的性能。
JEP 490: ZGC:刪除非分代模式
::: info JEP 490: ZGC: Remove the Non-Generational Mode
Remove the non-generational mode of the Z Garbage Collector (ZGC), keeping the generational mode as the default for ZGC.
:::
移除Z垃圾回收器(ZGC)的非分代模式,保留分代模式作為ZGC的默認(rèn)配置。
JEP 491: 無(wú)需固定即可同步虛擬線程
::: info JEP 491: Synchronize Virtual Threads without Pinning
Improve the scalability of Java code that uses synchronized methods and statements by arranging for virtual threads that block in such constructs to release their underlying platform threads for use by other virtual threads. This will eliminate nearly all cases of virtual threads being pinned to platform threads, which severely restricts the number of virtual threads available to handle an application's workload.
:::
本改進(jìn)旨在提升使用同步方法和語(yǔ)句的Java代碼的可擴(kuò)展性。其機(jī)制是:當(dāng)虛擬線程在此類同步結(jié)構(gòu)中阻塞時(shí),會(huì)主動(dòng)釋放其占用的平臺(tái)線程,以供其他虛擬線程使用。此舉將消除虛擬線程被“固定”在平臺(tái)線程上的絕大多數(shù)情況,從而避免其對(duì)應(yīng)用工作負(fù)載處理能力的嚴(yán)重限制。
JEP 492: 靈活的構(gòu)造函數(shù)體(第三次預(yù)覽)
::: info JEP 492: Flexible Constructor Bodies (Third Preview)
In constructors in the Java programming language, allow statements to appear before an explicit constructor invocation, i.e., super(..) or this(..). The statements cannot reference the instance under construction, but they can initialize its fields. Initializing fields before invoking another constructor makes a class more reliable when methods are overridden. This is a preview language feature.
:::
在 Java 編程語(yǔ)言的構(gòu)造函數(shù)中,允許在顯式構(gòu)造函數(shù)調(diào)用(即 super(..) 或 this(..))之前出現(xiàn)語(yǔ)句。這些語(yǔ)句不能引用正在構(gòu)建的實(shí)例,但可以初始化其字段。在調(diào)用另一個(gè)構(gòu)造函數(shù)之前初始化字段,可以在方法被重寫(xiě)時(shí)提高類的可靠性。這是一個(gè)預(yù)覽語(yǔ)言特性。
JEP 493: 無(wú)需 JMOD 即可鏈接運(yùn)行時(shí)圖像
::: info JEP 493: Linking Run-Time Images without JMODs
Reduce the size of the JDK by approximately 25% by enabling the jlink tool to create custom run-time images without using the JDK's JMOD files. This feature must be enabled when the JDK is built; it will not be enabled by default, and some JDK vendors may choose not to enable it.
:::
通過(guò)讓 jlink 工具能夠在不依賴 JDK 的 JMOD 文件的情況下創(chuàng)建自定義運(yùn)行時(shí)鏡像,可將 JDK 的體積減小約 25%。此功能需在構(gòu)建 JDK 時(shí)手動(dòng)啟用,它不會(huì)默認(rèn)生效,且部分 JDK 供應(yīng)商可能會(huì)選擇不啟用它。
JEP 494: 模塊導(dǎo)入聲明(第二次預(yù)覽)
::: info JEP 494: Module Import Declarations (Second Preview)
Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself. This is a preview language feature.
:::
增強(qiáng) Java 編程語(yǔ)言,使其能夠簡(jiǎn)潔地導(dǎo)入某個(gè)模塊所導(dǎo)出的所有包。這簡(jiǎn)化了模塊化庫(kù)的重用,且調(diào)用方代碼自身不必是模塊化的。這是一項(xiàng)預(yù)覽語(yǔ)言特性。
使用新特性導(dǎo)入整個(gè)模塊
假設(shè)有一個(gè)名為 com.example.utils 的模塊,其 module-info.java 文件導(dǎo)出了了一些包:
// module-info.java
module com.example.utils {
exports com.example.utils.math;
exports com.example.utils.logging;
}
在另一個(gè)非模塊化的應(yīng)用程序(即沒(méi)有 module-info.java)中,現(xiàn)在可以使用一種新的導(dǎo)入語(yǔ)句來(lái)一次性導(dǎo)入 com.example.utils 模塊導(dǎo)出的所有包。
// 使用 'import module' 關(guān)鍵字一次性導(dǎo)入整個(gè)模塊的所有導(dǎo)出包
import module com.example.utils.*;
public class MyApp {
public static void main(String[] args) {
// 現(xiàn)在可以直接使用被導(dǎo)入模塊中所有導(dǎo)出包下的類,而無(wú)需逐個(gè)導(dǎo)入
// 來(lái)自 com.example.utils.math 包
Calculator calc = new Calculator();
double result = calc.add(5, 3.14);
// 來(lái)自 com.example.utils.logging 包
Logger logger = new Logger();
logger.info("Result is: " + result);
}
}
與之前方式的對(duì)比
- 方式一(傳統(tǒng)非模塊化項(xiàng)目): 必須逐個(gè)導(dǎo)入所需的每個(gè)類或包。
import com.example.utils.math.Calculator; import com.example.utils.logging.Logger; // ... 還需要導(dǎo)入其他要用的類 ... - 方式二(模塊化項(xiàng)目): 即使只想用一兩個(gè)類,也必須在自己的 module-info.java 中聲明對(duì)整個(gè)模塊的依賴。
::: code-tabs
@tab module-info.java
@tab MyApp.javamodule my.app { requires com.example.utils; // ... 其他依賴 ... }
:::import com.example.utils..math.Calculator; - 使用新特性后的方式(簡(jiǎn)潔且無(wú)需模塊化):
- 無(wú)需自身的 module-info.java。
- 一行語(yǔ)句 import module com.example.utils.*; 即可獲得該模塊所有導(dǎo)出包的訪問(wèn)權(quán),無(wú)需再寫(xiě)多個(gè) import 語(yǔ)句。
之前在 JDK 23 中預(yù)覽過(guò),本次改動(dòng)點(diǎn):
- 解除任何模塊都不能聲明對(duì) java.base 模塊的傳遞依賴的限制
- 修改 java.se 模塊的聲明
- 允許 type-import-on-demand 聲明遮蔽模塊導(dǎo)入聲明
JEP 495: 簡(jiǎn)單源文件和實(shí)例主方法(第四次預(yù)覽)
::: info JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)
Evolve the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large. This is a preview language feature.
:::
擴(kuò)展 Java 編程語(yǔ)言,使初學(xué)者無(wú)需了解專為大型程序設(shè)計(jì)的語(yǔ)言功能,即可編寫(xiě)自己的第一個(gè)程序。初學(xué)者無(wú)需使用某種獨(dú)立的語(yǔ)言變體,即可為單類程序編寫(xiě)簡(jiǎn)化的聲明,然后隨著技能的增長(zhǎng)無(wú)縫擴(kuò)展他們的程序以使用更高級(jí)的功能。經(jīng)驗(yàn)豐富的開(kāi)發(fā)者同樣可以簡(jiǎn)潔地編寫(xiě)小型程序,而不必使用那些為大規(guī)模編程設(shè)計(jì)的結(jié)構(gòu)。
簡(jiǎn)單說(shuō)就是省略顯式類聲明和 public static 修飾符,簡(jiǎn)化輸出語(yǔ)句,來(lái)簡(jiǎn)化入門(mén)代碼和腳本開(kāi)發(fā)。
void main() {
println("Hello Java 23!"); // 隱式調(diào)用 System.out.println
}
改動(dòng)點(diǎn):將隱式聲明的類和實(shí)例主方法重命名為簡(jiǎn)單源文件和實(shí)例主要方法
JEP 496: 基于抗量子模塊格的密鑰封裝機(jī)制
::: info JEP 496: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism
Enhance the security of Java applications by providing an implementation of the quantum-resistant Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM). Key encapsulation mechanisms (KEMs) are used to secure symmetric keys over insecure communication channels using public key cryptography. ML-KEM is designed to be secure against future quantum computing attacks. It has been standardized by the United States National Institute of Standards and Technology (NIST) in FIPS 203.
:::
通過(guò)提供抗量子的基于模塊格的密鑰封裝機(jī)制(ML-KEM)實(shí)現(xiàn),增強(qiáng)Java應(yīng)用程序的安全性。密鑰封裝機(jī)制(KEM)利用公鑰密碼學(xué),在不安全通信信道中保護(hù)對(duì)稱密鑰的安全傳輸。ML-KEM的設(shè)計(jì)旨在抵御未來(lái)量子計(jì)算攻擊,并已由美國(guó)國(guó)家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)在FIPS 203中完成標(biāo)準(zhǔn)化。
JEP 497: 基于模塊格的抗量子數(shù)字簽名算法
::: info JEP 497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm
Enhance the security of Java applications by providing an implementation of the quantum-resistant Module-Lattice-Based Digital Signature Algorithm (ML-DSA). Digital signatures are used to detect unauthorized modifications to data and to authenticate the identity of signatories. ML-DSA is designed to be secure against future quantum computing attacks. It has been standardized by the United States National Institute of Standards and Technology (NIST) in FIPS 204.
:::
通過(guò)提供抗量子計(jì)算的基于模塊格的數(shù)字簽名算法(ML-DSA)實(shí)現(xiàn),增強(qiáng)Java應(yīng)用程序的安全性。數(shù)字簽名技術(shù)用于檢測(cè)數(shù)據(jù)的非法篡改,并對(duì)簽名者身份進(jìn)行認(rèn)證。ML-DSA的設(shè)計(jì)旨在抵御未來(lái)量子計(jì)算攻擊,并已由美國(guó)國(guó)家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)在FIPS 204中完成標(biāo)準(zhǔn)化。
JEP 498: 在 sun.misc.Unsafe 中使用內(nèi)存訪問(wèn)方法時(shí)發(fā)出警告
::: info JEP 498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe
Issue a warning at run time on the first occasion that any memory-access method in sun.misc.Unsafe is invoked. All of these unsupported methods were terminally deprecated in JDK 23. They have been superseded by standard APIs, namely the VarHandle API (JEP 193, JDK 9) and the Foreign Function & Memory API (JEP 454, JDK 22). We strongly encourage library developers to migrate from sun.misc.Unsafe to supported replacements, so that applications can migrate smoothly to modern JDK releases.
:::
在運(yùn)行時(shí)首次調(diào)用 sun.misc.Unsafe 中的任何內(nèi)存訪問(wèn)方法時(shí)發(fā)出警告。 所有這些不受支持的方法已在 JDK 23 中被最終標(biāo)記為棄用。它們已被標(biāo)準(zhǔn) API 所取代,即 VarHandle API(JEP 193,JDK 9)和外部函數(shù)與內(nèi)存 API(JEP 454,JDK 22)。強(qiáng)烈建議庫(kù)開(kāi)發(fā)者從 sun.misc.Unsafe 遷移至受支持的替代方案,以確保應(yīng)用能夠順利過(guò)渡到現(xiàn)代 JDK 版本。
創(chuàng)建 sun.misc.Unsafe 類是為了為 Java 類提供一種執(zhí)行低級(jí)操作的機(jī)制。它的大多數(shù)方法用于訪問(wèn)內(nèi)存,無(wú)論是在 JVM 的垃圾收集堆中還是在堆外內(nèi)存中,這些內(nèi)存不受 JVM 控制。正如類名所示,這些內(nèi)存訪問(wèn)方法是不安全的。
JEP 499: 結(jié)構(gòu)化并發(fā)(第四次預(yù)覽)
::: info JEP 499: Structured Concurrency (Fourth Preview)
Simplify concurrent programming by introducing an API for structured concurrency. Structured concurrency treats groups of related tasks running in different threads as a single unit of work, thereby streamlining error handling and cancellation, improving reliability, and enhancing observability. This is a preview API.
:::
通過(guò)引入結(jié)構(gòu)化并發(fā) API 來(lái)簡(jiǎn)化并發(fā)編程。結(jié)構(gòu)化并發(fā)將不同線程中運(yùn)行的相關(guān)任務(wù)組視為單個(gè)工作單元,從而簡(jiǎn)化錯(cuò)誤處理和取消,提高可靠性并增強(qiáng)可觀測(cè)性。這是一個(gè)預(yù)覽 API。
JEP 501: 棄用 32 位 x86 端口并將其刪除
::: info JEP 501: Deprecate the 32-bit x86 Port for Removal
Deprecate the 32-bit x86 port, with the intent to remove it in a future release. This will thereby deprecate the Linux 32-bit x86 port, which is the only 32-bit x86 port remaining in the JDK. It will also, effectively, deprecate any remaining downstream 32-bit x86 ports. After the 32-bit x86 port is removed, the architecture-agnostic Zero port will be the only way to run Java programs on 32-bit x86 processors.
:::
棄用 32 位 x86 端口,并計(jì)劃在未來(lái)版本中將其移除。此舉將導(dǎo)致目前 JDK 中唯一剩余的 32 位 x86 端口——Linux 32 位 x86 端口被棄用,同時(shí)也將實(shí)質(zhì)上棄用所有下游衍生的 32 位 x86 移植版本。在該端口被移除后,與架構(gòu)無(wú)關(guān)的 Zero 移植版本將成為在 32 位 x86 處理器上運(yùn)行 Java 程序的唯一方式。