Java 24新特性概述
Java 24于2025年3月18日正式发布,这是一个非LTS版本:
Java 24正好24个JEP,是继Java 11(18个JEP)之后的新纪录,乍一看挺多,但对于大多数程序员来说,在日常编程中并不会直观地感到有特别大的变化,下面我们一起来看看:
-
JEP 404:Generational Shenandoah (Experimental )分代Shenandoan(实验特性)
-
JEP 450:Compact Object Headers (Experimental) 压缩对象头(实验特性)
-
JEP 472:Prepare to Restrict the Use of JNI 准备限制JNI的使用
-
JEP 475:Late Barrier Expansion for G1 G1后期屏障扩展
-
JEP 478:Key Derivation Function API (Preview) 密钥派生函数 API(首次预览)
-
JEP 479:Remove the Windows 32-bit x86 Port 删除Windows 32位 x86端口
-
JEP 483:Ahead-of-Time Class Loading & Linking 提前类加载和链接
-
JEP 484: Class-File API 类文件 API
-
JEP 485:Stream Gatherers 流收集器
-
JEP 486:Permanently Disable the Security Manager 永久禁用Security Manager
-
JEP 487:Scoped Values (Fourth Preview) 作用域值(第四次预览)
-
JEP 488:Primitive Types in Patterns, instanceof, and switch (Second Preview) 模式中的原始类型、instanceof和switch(第二次预览)
-
JEP 489:Vector API 向量API(第九轮孵化)
-
JEP 490:ZGC: Remove the Non-Generational Mode 删除非分代模式
-
JEP 491:Synchronize Virtual Threads without Pinning 同步虚拟线程而不固定
-
JEP 492:Flexible Constructor Bodies (Third Preview) 灵活的构造函数体(第三次预览)
-
JEP 493:Linking Run-Time Images without JMODs 链接没有JMOD的运行时图像
-
JEP 494:Module Import Declarations (Second Preview) 模块导入声明(第二次预览)
-
JEP 495:Simple Source Files and Instance Main Methods (Fourth Preview) 简单源文件和实例main方法(第四次预览)
-
JEP 496:Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism 基于模块格的抗量子的密钥封装机制
-
JEP 497:Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm 基于模块格的抗量子的数字签名算法
-
JEP 498:Warn upon Use of Memory-Access Methods in sun.misc.Unsafe 在Unsafe中使用内存访问会发出警告
-
JEP 499:Structured Concurrency (Fourth Preview) 结构化并发(第四次预览)
-
JEP 501:Deprecate the 32-bit x86 Port for Removal 弃用32位Linux x86端口以便删除
更多内容读者可自行阅读:OpenJDK Java 24文档
一、JEP 404:分代Shenandoan(实验特性)
Java 15引入了两个新的垃圾回收器——ZGC和Shenandoah,两者的暂停时间都小于10ms,不过都没有分代(新生代和老年代),带来的后果就是必须给这俩垃圾回收器分配更多的空间,而且在回收对象时需要更频繁地标记长期存在的对象。
ps:ZGC 在Java 21引入了“分代模式”。
所以为了提Shenandoah的吞吐量和内存利用率,Java 24引入了“分代模式”,Shenandoah GC的分代模式目前处于实验阶段,使用时需要增加如下参数:
-XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational
二、JEP 450: 压缩对象头(实验特性)
每个Java对象都有一个对象头,对象头由一个64位的Mark Word和一个32位的Class word组成,对象头在64位平台上是128位,与对象的大小无关,如果存在大量对象,那也意味着占用大量内存。
该功能就是把Mark word和Class work合并起来,并生成64位的压缩后的对象头,从而减少Java程序的CPU和内存占用率,这也是实验特性,所以用的时候也需要加上如下参数:
-XX:+UnlockExperimentalVMOptions -XX:+UseCompactObjectHeaders
三、JEP 472: 准备限制JNI的使用
JNI允许Java程序与本地方法接口(JNI)交互,但同时也会带来风险,比如JVM崩溃、不可预知的GC行为,Java 19的外部函数和内存API(FFM API)就是为了替代JNI而引入的。
四、JEP 475: G1后期屏障扩展
该功能有助于提高云原生中Java的性能,因为它可以减少JVM预热期间的CPU和内存开销。
GC 屏障包含有关应用程序内存访问的信息。JIT 编译器在早期编译阶段像任何其他节点一样扩展 GC barrier 节点。但这会导致大量的编译开销。后期 G1 GC barrier 扩展背后的想法是让 JIT 编译器尽可能晚地扩展 barrier 节点,直到必须发出机器代码的阶段。这样,GC 特有的内存访问指令就根据相关的 barrier 信息转换成机器码,这些信息在编译初期就被标记了。JDK开发人员测试的结果是,性能提升了大概10~20%。
ps:ZGC自Java 14依赖就使用了后期屏障扩展。
五、JEP 478:密钥派生函数API(首次预览)
传统公钥的加密算法越来越容易受到黑客攻击,尤其是在量子计算方面,所以Java平台需要为开发人员提供实现后量子加密算法的方法。
所以Java 24引入了这样的API,我们可以通过新类javax.crypto.KDF来实现:
void main() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
// 1. 获取KDF
KDF hkdf = KDF.getInstance("HKDF-SHA256");
// 2. 指定派生参数
AlgorithmParameterSpec params =
HKDFParameterSpec.ofExtract()
// 2.1. 密码
.addIKM("the super secret passphrase".getBytes(StandardCharsets.UTF_8))
// 2.2. 盐值
.addSalt("the salt".getBytes(StandardCharsets.UTF_8))
// 2.3. 应用程序信息
.thenExpand("my derived key".getBytes(StandardCharsets.UTF_8), 32);
// 3. 派生一个32位的AES密钥
SecretKey key = hkdf.deriveKey("AES", params);
System.out.println("key = " + HexFormat.of().formatHex(key.getEncoded()));
}
六、JEP 479:删除Windows 32位 x86端口
在Java 21中,Windows的32位Java端口就被标记为”弃用“,所以在Java 24中正式被删除。
七、JEP 483:提前类加载和链接
Java程序的启动和预热时间比较长,尤其是在云原生中,启动需要几秒,预热可能要几分钟。
该JEP的目标就是降低Java启动和预热的时间,在准备阶段,将读取、解析、加载和链接应用程序所需的所有类保存在缓存中。当应用程序启动时,不再需要执行这些步骤,应用程序可以通过缓存直接访问加载的类和链接的类。
八、JEP 484: 类文件 API
大多数程序员仅会通过工具间接调用此API,而且永远不会直接调用,所以就不做介绍了,感兴趣的可以去官网研究下。
九、JEP 485: 流收集器(转正)
流收集器在 JDK 22 中由 JEP 461 提议作为预览功能。
并在 JDK 23 中由 JEP 473 重新预览。
在 JDK 24 中正式转正,没任何更改。
ps:可以参考Java 22对这一特性的介绍。
十、JEP 486:永久禁用Security Manager
Security Manager API 从第一个 Java 版本开始就已经存在。它旨在通过最小权限原则保护应用程序:默认情况下,代码不受信任,开发人员必须明确授予特定代码访问某些资源的权限。
在实践中,授予权限的过程非常复杂,以至于很少有应用程序真正使用安全管理器,在Java 17中就被标记为”弃用“,Java 24正式禁用。
十一、JEP 487:作用域值(第四次预览)
作用域值API 由 JEP 429 (JDK 20) 提议孵化。
由 JEP 446 (JDK 21) 提议预览。
随后由 JEP 464 (JDK 22) 和 JEP 481 (JDK 23) 改进和完善。
在 JDK 24 中再次重新预览,并作如下改进:
从
ScopedValue
类中删除了callWhere
和runWhere
方法使用一个或多个绑定范围值的唯一方法是通过
ScopedValue.Carrier.call
和ScopedValue.Carrier.run
方法。
ps:可以参考Java 21对该功能的介绍。
十二、JEP 488: 模式中的原始类型、instanceof和switch(第二次预览)
此功能最初由 JEP 455 提出,并在 JDK 23 中作为预览功能提供。
Java 24建议第二次预览它,不做任何更改。
ps:可以参考Java 23对该功能的介绍。
十三、JEP 489:向量API(第九轮孵化)
在 JEP 338 (JDK 16)中提出了 Vector API,并将其作为 孵化 API。
我们建议在 JEP 414 中进行更多轮次的孵化 (集成到 JDK 17 中)、JEP 417 (JDK 18)、JEP 426 (JDK 19)、 JEP 438 (JDK 20)、JEP 448 (JDK 21)、JEP 460 (JDK 22) 和 JEP 469 (JDK 23)。
JDK 24 中建议重新孵化 API。
孵化挺久了,暂时可以先参考Java 16对该特性的介绍,待正式开始预览再作详解。
十四、JEP 490:ZGC:删除非分代模式
Java 21引入了ZGC垃圾回收器的"分代模式"以优化垃圾回收性能,从Java 23开始”分代模式“作为ZGC的默认模式,但是仍然可以通过参数来使用非分代模式,为了避免这两种模式同时存在,在Java 24删除ZGC的非分代模式。
十五、JEP 491:同步虚拟线程而不固定
自从 Java 21 中引入以来,当在同步块中调用阻塞代码时,虚拟线程被“固定”到其载体线程,即载体线程被阻塞,在此期间无法为任何其他虚拟线程提供服务。这可能会导致整个应用程序冻结。
从 Java 24 开始,这个问题已成为过去。在同步块中调用阻塞代码时,虚拟线程现在与载体线程分离,然后载体线程可以执行其他虚拟线程。
ps:虚拟线程可以参考这篇文章:Java 21的虚拟线程是怎么回事
十六、JEP 492:灵活的构造函数体(第三次预览)
此功能在Java 22中进行首次预览,不过标题是super(...) 之前的语句。
Java 23进行第二次预览。
Java 24进行第三次预览,并没有重大改变。
ps:可以参考Java 22对该功能的介绍。
十七、JEP 493:链接没有JMOD的运行时图像
这个好像跟我们关系不大,感兴趣的同学可以去官网研究一下。
十八、JEP 494:模块导入声明(第二次预览)
此功能在Java 23中首次预览。
在Java 24中重新预览该功能,并增加了两个功能:
允许在导入 java.se 模块时导入整个 Java SE API;
当多个导入的模块包含具有相同名称的类时,通过允许按需导入声明来隐藏模块导入声明,从而消除歧义。
如下:
import module java.base; // exports java.util with a public Date class
import module java.sql; // exports java.sql with a public Date class
import java.sql.Date; // resolve the ambiguity of the name Date
Date d = ... // Date is resolved to java.sql.Date
十九、JEP 495:简单源文件和实例main方法(第四次预览)
此功能最初是由 JEP 445 (JDK 21) 以及随后由 JEP 463 改进和改进 (JDK 22) 和 JEP 477 (JDK 23)。
Java 24建议第四次预览它。
ps:可以参考Java 21对该功能的介绍,标题是JEP 445:未命名类和实例主要方法(第一次预览)
二十、JEP 496:基于模块格的抗量子的密钥封装机制
未来的量子计算机威胁着 RSA 和 Diffie-Hellman 等传统加密算法。使用 ML-KEM(基于模块格的密钥封装机制 - 该链接指向美国国家标准与技术研究所网站上的机制描述)应该可以安全地交换密钥,即使在量子计算机时代也是如此:
void main() throws GeneralSecurityException {
// Step 1 (Receiver): Create a ML-KEM public/private key pair:
KeyPairGenerator generator = KeyPairGenerator.getInstance("ML-KEM");
KeyPair keyPair = generator.generateKeyPair();
PublicKey receiverPublicKey = keyPair.getPublic();
PrivateKey receiverPrivateKey = keyPair.getPrivate();
// Step 2 (Sender, has the receiver's public key):
// Create a session key and encapsulate it:
KEM kem = KEM.getInstance("ML-KEM");
KEM.Encapsulator encapsulator = kem.newEncapsulator(receiverPublicKey);
KEM.Encapsulated encapsulated = encapsulator.encapsulate();
SecretKey sessionKey = encapsulated.key();
System.out.println(HexFormat.of().formatHex(sessionKey.getEncoded()));
byte[] keyEncapsulationMessage = encapsulated.encapsulation();
// Step 3 (Receiver, has the sender's key encapsulation message):
// Decapsulate the session key:
KEM kr = KEM.getInstance("ML-KEM");
KEM.Decapsulator decapsulator = kr.newDecapsulator(receiverPrivateKey);
SecretKey decapsulatedSessionKey = decapsulator.decapsulate(keyEncapsulationMessage);
System.out.println(HexFormat.of().formatHex(decapsulatedSessionKey.getEncoded()));
// Now sender and receiver can exchange messages
// using the securely transmitted session key.
// . . .
}
二十一、JEP 497:基于模块格的抗量子的数字签名算法
与上一节中描述的 ML-KEM 方法类似,ML-DSA 方法(基于模块格的数字签名算法 - 此链接也指向美国国家标准与技术研究院)也被添加到 JDK 中,该方法也是量子安全的:
import java.security.Signature;
void main() throws GeneralSecurityException {
// Step 1 (Sender): Create a ML-KEM public/private key pair:
KeyPairGenerator generator = KeyPairGenerator.getInstance("ML-DSA");
KeyPair keyPair = generator.generateKeyPair();
PublicKey senderPublicKey = keyPair.getPublic();
PrivateKey senderPrivateKey = keyPair.getPrivate();
// Step 2 (Sender): Sign a message using the private key:
byte[] message = "Roses bloom nightly.".getBytes(StandardCharsets.UTF_8);
Signature signer = Signature.getInstance("ML-DSA");
signer.initSign(senderPrivateKey);
signer.update(message);
byte[] signature = signer.sign();
// Step 3 (Receiver): Verify the message using the sender's public key:
Signature signatureVerifier = Signature.getInstance("ML-DSA");
signatureVerifier.initVerify(senderPublicKey);
signatureVerifier.update(message);
boolean verified = signatureVerifier.verify(signature);
. . .
}
二十二、JEP 498:在Unsafe中使用内存访问会发出警告
Java 1.4 中引入的 sun.misc.Unsafe
类(20 多年前)一直是直接访问工作内存(堆和本机内存,即不受垃圾回收器管理的内存)的强大但危险的工具。
由于许多库在没有这些检查的情况下使用了sun.misc.Unsafe
的方法,因此引入了两个更可靠和安全的API,即变量句柄和外部函数和内存API。在Java 23已经将sun.misc.Unsafe中的内存访问方法标记为“弃用”,在Java 24如果还用的话,JVM会发出警告。
二十三、JEP 499:结构化并发(第四次预览)
ps:可以参考Java 21对该功能的介绍。
二十四、JEP 501:弃用32位Linux x86端口以便删除
该功能弃用了 32 位 Linux x86 端口,这是 OpenJDK 中仅存的 32 位 x86 端口,并打算在后续版本中删除它。
END:更多新特性的介绍,推荐移步至👉 Java新特性学习导航(8~24 持续更新)👈