<p>>Java语言特性系列</p>
- Java5的新特性
- Java6的新特性
- Java7的新特性
- Java8的新特性
- Java9的新特性
- Java10的新特性
- Java11的新特性
- Java12的新特性
- Java13的新特性
- Java14的新特性
- Java15的新特性
- Java16的新特性
- Java17的新特性
- Java18的新特性
- Java19的新特性
- Java20的新特性
- Java21的新特性
- Java22的新特性
- Java23的新特性
- Java24的新特性
- Java25的新特性
- Java26的新特性
序
本文主要讲述一下Java25的新特性
版本号
openjdk version "25" 2025-09-16
OpenJDK Runtime Environment (build 25+36-3489)
OpenJDK 64-Bit Server VM (build 25+36-3489, mixed mode, sharing)
>从version信息可以看出是build 25+36
特性列表
JEP 470: PEM Encodings of Cryptographic Objects (Preview)
本特性为Java平台引入了一套简洁、易用且线程安全的API(Preview版本),用于在 PEM(Privacy-Enhanced Mail)文本与各类密码学对象(密钥、证书、CRL 等)之间进行双向转换,解决开发者长期需要手写解析/格式化逻辑的痛点。
-
DEREncodable 标记接口 统一标识可参与 PEM 编解码的已有类型: AsymmetricKey、X509Certificate、X509CRL、KeyPair、EncryptedPrivateKeyInfo、PKCS8EncodedKeySpec、X509EncodedKeySpec 以及新引入的 PEMRecord。
-
PEMEncoder / PEMDecoder 不可变、可复用、线程安全。 支持直接编解码字符串或字节流,提供 encode(DerEncodable) / decode(String/InputStream) 等便捷方法。 通过 withEncryption(char[] password) / withDecryption(…) 一键加解密私钥;默认算法可在安全属性文件中配置(当前为 PBEWithHmacSHA256AndAES_128)。 通过 withFactory(Provider) 可指定特定加密提供者。
-
PEMRecord 记录类 用于处理平台暂无对应 API 的 PEM 类型(如 PKCS#10 请求)或需要保留 PEM 首部前导数据的场景。
-
EncryptedPrivateKeyInfo 增强 新增静态工厂方法 encryptKey(…) 与实例方法 getKey(…),方便先加密成 EncryptedPrivateKeyInfo 再编码为 PEM,或解码后直接解密拿到 PrivateKey。
使用示例
public class PEMEncoding {
public static void main() throws NoSuchAlgorithmException {
// Enable preview features: --enable-preview --release 25
// 1. Generate an EC key pair
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 2. Encode public key to PEM
String publicKeyPEM = PEMEncoder.of()
.encodeToString(keyPair.getPublic());
System.out.println("Public Key PEM:\n" + publicKeyPEM);
// 3. Encode a private key to encrypted PEM
char[] password = "secret".toCharArray();
String privateKeyPEM = PEMEncoder.of()
.withEncryption(password)
.encodeToString(keyPair.getPrivate());
System.out.println("Encrypted Private Key PEM:\n" + privateKeyPEM);
// 4. Decode a public key
PublicKey decodedPubKey = PEMDecoder.of()
.decode(publicKeyPEM, PublicKey.class);
System.out.println("Decoded Public Key Algo: " + decodedPubKey.getAlgorithm());
// 5. Decode encrypted private key
PrivateKey decodedPrivateKey = PEMDecoder.of()
.withDecryption(password)
.decode(privateKeyPEM, PrivateKey.class);
System.out.println("Decoded Private Key Algo: " + decodedPrivateKey.getAlgorithm());
}
}
编译及运行
javac --release 25 --enable-preview PEMEncoding.java
java --enable-preview PEMEncoding
JEP 502: Stable Values (Preview)
本特性引入了一种名为 Stable Values(稳定值) 的 API,用于支持延迟初始化的不可变数据持有者对象。这一特性在 JDK 25 中以预览功能形式提供,旨在提升 Java 应用的启动性能与并发安全性,同时保留 final 字段的优化能力(如常量折叠)。 Stable Values填补了final字段与可变字段之间的空白,在保持不可变性和线程安全的同时,支持按需初始化,特别适用于启动时需要延迟加载资源的大型应用场景。
使用示例如下:
class OrderController {
// OLD:
// private Logger logger = null;
// NEW:
private final StableValue<logger> logger = StableValue.of();
Logger getLogger() {
return logger.orElseSet(() -> Logger.create(OrderController.class));
}
void submitOrder(User user, List<product> products) {
getLogger().info("order started");
...
getLogger().info("order submitted");
}
}
由于是预览版本,所以需要--enable-preview
启用
javac --release 25 --enable-preview Main.java
java --enable-preview Main
JEP 503: Remove the 32-bit x86 Port
在JDK21的JEP 449: Deprecate the Windows 32-bit x86 Port for Removal已经废弃了对Windows 32位 x86的移植 在JDK24的JEP 479: Remove the Windows 32-bit x86 Port删除了相关源代码、移除了对windows 32位相关构建支持 在JDK24的JEP 501: Deprecate the 32-bit x86 Port for Removal废弃了对32位x86的移植,但是可以通过--enable-deprecated-ports=yes
来启用构建 在JDK25Z则删除了相关源代码、移除了相关构建支持
JEP 505: Structured Concurrency (Fifth Preview)
>JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator >JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator >JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview >JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview >JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview >JDK24的JEP 499: Structured Concurrency (Fourth Preview)作为第四次preview >JDK25作为第五次preview
使用示例如下:
Response handle() throws InterruptedException {
try (var scope = StructuredTaskScope.open()) {
Subtask<string> user = scope.fork(() -> findUser());
Subtask<integer> order = scope.fork(() -> fetchOrder());
scope.join(); // Join subtasks, propagating exceptions
// Both subtasks have succeeded, so compose their results
return new Response(user.get(), order.get());
}
}
JEP 506: Scoped Values
JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview JDK22的JEP 462: Structured Concurrency (Second Preview)作为第二次preview JDK23的JEP 480: Structured Concurrency (Third Preview)作为第三次preview JDK24的JEP 487: Scoped Values (Fourth Preview)作为第四次preview,与JDK23不同的是callWhere以及runWhere方法从ScopedValue类中移除,可以使用ScopedValue.where()再链式调用run(Runnable)或者call(Callable)
JDK25作为第五次preview,有个改动就是ScopedValue.orElse方法不再接受null作为参数
示例:
class Framework {
private static final ScopedValue<frameworkcontext> CONTEXT
= ScopedValue.newInstance(); // (1)
void serve(Request request, Response response) {
var context = createContext(request);
where(CONTEXT, context) // (2)
.run(() -> Application.handle(request, response));
}
public PersistedObject readKey(String key) {
var context = CONTEXT.get(); // (3)
var db = getDBConnection(context);
db.readKey(key);
}
}
>在 (1) 中,框架声明了一个作用域值,而不是一个thread local变量。在 (2),serve方法调用where … run而不是thread local的set方法。run方法提供了数据的单向共享serve方法到readKey方法。(3) 读取的值是由Framework.serve的时候写入的。
JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
JDK19的JEP 405: Record Patterns (Preview)将Record的模式匹配作为第一次preview JDK20的JEP 432: Record Patterns (Second Preview)作为Record模式匹配第二次preview JDK21的JEP 440: Record Patterns则将Record模式匹配正式发布 JDK23的JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)将原始类型的匹配作为第一次preview JDK24的JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)作为第二次preview JDK25作为第三次preview
record Point(int x, int y) {}
// As of Java 21
static void printSum(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println(x+y);
}
}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}
// As of Java 21
static void printUpperLeftColoredPoint(Rectangle r) {
if (r instanceof Rectangle(ColoredPoint ul, ColoredPoint lr)) {
System.out.println(ul.c());
}
}
static void printColorOfUpperLeftPoint(Rectangle r) {
if (r instanceof Rectangle(ColoredPoint(Point p, Color c),
ColoredPoint lr)) {
System.out.println(c);
}
}
>但是这个只是支持Record类型
在JDK14JEP 305: Pattern Matching for instanceof (Preview)作为preview 在JDK15JEP 375: Pattern Matching for instanceof (Second Preview)作为第二轮的preview 在JDK16JEP 394: Pattern Matching for instanceof转正 JDK17引入JEP 406: Pattern Matching for switch (Preview) JDK18的JEP 420: Pattern Matching for switch (Second Preview)则作为第二轮preview JDK19的JEP 427: Pattern Matching for switch (Third Preview)作为第三轮preview JDK20的JEP 433: Pattern Matching for switch (Fourth Preview)作为第四轮preview JDK21的JEP 441: Pattern Matching for switch将Pattern Matching for switch作为正式版本发布,示例如下
// Prior to Java 21
static String formatter(Object obj) {
String formatted = "unknown";
if (obj instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (obj instanceof Long l) {
formatted = String.format("long %d", l);
} else if (obj instanceof Double d) {
formatted = String.format("double %f", d);
} else if (obj instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
// As of Java 21
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
}
// As of Java 21
static void testFooBarNew(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
// As of Java 21
static void testStringEnhanced(String response) {
switch (response) {
case null -> { }
case "y", "Y" -> {
System.out.println("You got it");
}
case "n", "N" -> {
System.out.println("Shame");
}
case String s
when s.equalsIgnoreCase("YES") -> {
System.out.println("You got it");
}
case String s
when s.equalsIgnoreCase("NO") -> {
System.out.println("Shame");
}
case String s -> {
System.out.println("Sorry?");
}
}
}
// As of Java 21
static void exhaustiveSwitchWithBetterEnumSupport(CardClassification c) {
switch (c) {
case Suit.CLUBS -> {
System.out.println("It's clubs");
}
case Suit.DIAMONDS -> {
System.out.println("It's diamonds");
}
case Suit.HEARTS -> {
System.out.println("It's hearts");
}
case Suit.SPADES -> {
System.out.println("It's spades");
}
case Tarot t -> {
System.out.println("It's a tarot");
}
}
}
// As of Java 21
sealed interface Currency permits Coin {}
enum Coin implements Currency { HEADS, TAILS }
static void goodEnumSwitch1(Currency c) {
switch (c) {
case Coin.HEADS -> { // Qualified name of enum constant as a label
System.out.println("Heads");
}
case Coin.TAILS -> {
System.out.println("Tails");
}
}
}
static void goodEnumSwitch2(Coin c) {
switch (c) {
case HEADS -> {
System.out.println("Heads");
}
case Coin.TAILS -> { // Unnecessary qualification but allowed
System.out.println("Tails");
}
}
}
// As of Java 21
static void testNew(Object obj) {
switch (obj) {
case String s when s.length() == 1 -> ...
case String s -> ...
...
}
}
>但是JDK21还不支持原始类型的匹配
而支持原始类型的匹配使用示例如下:
switch (x.getStatus()) {
case 0 -> "okay";
case 1 -> "warning";
case 2 -> "error";
default -> "unknown status: " + x.getStatus();
}
switch (x.getStatus()) {
case 0 -> "okay";
case 1 -> "warning";
case 2 -> "error";
case int i -> "unknown status: " + i;
}
switch (x.getYearlyFlights()) {
case 0 -> ...;
case 1 -> ...;
case 2 -> issueDiscount();
case int i when i >= 100 -> issueGoldCard();
case int i -> ... appropriate action when i > 2 && i < 100 ...
}
long v = ...;
switch (v) {
case 1L -> ...;
case 2L -> ...;
case 10_000_000_000L -> ...;
case 20_000_000_000L -> ...;
case long x -> ... x ...;
}
if (roomSize instanceof byte) { // check if value of roomSize fits in a byte
... (byte) roomSize ... // yes, it fits! but cast is required
}
另外针对instanceof示例如下:
byte b = 42;
b instanceof int; // true (unconditionally exact)
int i = 42;
i instanceof byte; // true (exact)
int i = 1000;
i instanceof byte; // false (not exact)
int i = 16_777_217; // 2^24 + 1
i instanceof float; // false (not exact)
i instanceof double; // true (unconditionally exact)
i instanceof Integer; // true (unconditionally exact)
i instanceof Number; // true (unconditionally exact)
float f = 1000.0f;
f instanceof byte; // false
f instanceof int; // true (exact)
f instanceof double; // true (unconditionally exact)
double d = 1000.0d;
d instanceof byte; // false
d instanceof int; // true (exact)
d instanceof float; // true (exact)
Integer ii = 1000;
ii instanceof int; // true (exact)
ii instanceof float; // true (exact)
ii instanceof double; // true (exact)
Integer ii = 16_777_217;
ii instanceof float; // false (not exact)
ii instanceof double; // true (exact)
JEP 508: Vector API (Tenth Incubator)
JDK16引入了JEP 338: Vector API (Incubator)提供了jdk.incubator.vector来用于矢量计算 JDK17进行改进并作为第二轮的incubatorJEP 414: Vector API (Second Incubator) JDK18的JEP 417: Vector API (Third Incubator)进行改进并作为第三轮的incubator JDK19的JEP 426:Vector API (Fourth Incubator)作为第四轮的incubator JDK20的JEP 438: Vector API (Fifth Incubator)作为第五轮的incubator JDK21的JEP 448: Vector API (Sixth Incubator)作为第六轮的incubator JDK22的JEP 460: Vector API (Seventh Incubator)作为第七轮的incubator JDK23的JEP 469: Vector API (Eighth Incubator)作为第八轮incubator JDK24的JEP 489: Vector API (Ninth Incubator)则作为第九轮incubator,与JDK23相比做了一些变动:比如引入了一个新的基于值的类Float16,用于表示IEEE 754二进制16格式的16位浮点数。
JDK25作为第十轮incubator,主要变化是:VectorShuffle现在支持访问和访问MemorySegment,该实现是通过Foreign Function & Memory API (JEP 454) 而不是通过HotSpot内部的C++代码,提高了可维护性,另外对Float16值的加法、减法、除法、乘法、平方根和fused乘法/加法运算现在支持x64 cpu自动矢量化
JEP 509: JFR CPU-Time Profiling (Experimental)
本特性引入了实验版的CPU-Time Profiling,可以捕获更准确的CPU时间分析信息 使用示例
$ java -XX:StartFlightRecording=jdk.CPUTimeSample#enabled=true,filename=profile.jfr ...
$ jfr view cpu-time-hot-methods profile.jfr
配合jcmd使用如下
jcmd <pid> JFR.start settings=/tmp/cpu_profile.jfc duration=4m
jcmd <pid> JFR.stop
JEP 510: Key Derivation Function API
JDK 21中包含的KEM API(JEP 452)是HPKE的一个组成部分,标志着Java朝着HPKE迈出的第一步,并为后量子挑战做好了准备。 在JDK24的JEP 478: Key Derivation Function API (Preview)中提出了HPKE的另一个组成部分,作为这一方向上的下一步:密钥派生函数(KDFs)的API,作为预览版本 在JDK25转为正式版,无需--enable-preview
参数
使用示例如下:
// Create a KDF object for the specified algorithm
KDF hkdf = KDF.getInstance("HKDF-SHA256");
// Create an ExtractExpand parameter specification
AlgorithmParameterSpec params =
HKDFParameterSpec.ofExtract()
.addIKM(initialKeyMaterial)
.addSalt(salt).thenExpand(info, 32);
// Derive a 32-byte AES key
SecretKey key = hkdf.deriveKey("AES", params);
// Additional deriveKey calls can be made with the same KDF object
JEP 511: Module Import Declarations
>与JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)类似,本特性主要是为了简化语法方便新手使用,通过新引入module的import,来一次性导入module下所有package底下的类
JDK23的JEP 476: Module Import Declarations (Preview)作为第一个preview JDK24的JEP 494: Module Import Declarations (Second Preview)作为第二次preview,与JDK23不同的是取消了模块不允许声明对java.base模块传递依赖的限制,并修订了java.se模块声明,使其传递性地依赖于java.base模块。这些变化意味着导入java.se模块将按需导入整个Java SE API。此外,现在允许按需声明的类型导入声明覆盖模块导入声明。 JDK25作为正式版,没有变化
示例:
import module java.base; // 包含了import java.io.*; import java.util.*;
import module java.base; // exports java.util, which has a public Date class
import module java.sql; // exports java.sql, which has a public Date class
import java.sql.Date; // resolve the ambiguity of the simple name Date!
...
Date d = ... // Ok! Date is resolved to java.sql.Date
...
>由于是正式版,不再需要使用--enable-preview
参数来开启
JEP 512: Compact Source Files and Instance Main Methods
JDK21的JEP 445: Unnamed Classes and Instance Main Methods (Preview)作为首次preview,引入了未命名的类和实例main方法特性可以简化hello world示例,方便java新手入门 JDK22的JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)作为第二次的preview JDK23的JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)作为第三次preview JDK24的JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)则作为第四次preview JDK25作为正式版本,有些改动:
- console I/O的新IO类现在位于java.lang,而不是java.io包,现在隐式导入到每个源文件
- IO类的静态方法不再隐式导入compact source files,需要显示导入
- IO类的实现基于System.out及System.in,而非java.io.Console类
示例如下:
void main() {
String name = IO.readln("Please enter your name: ");
IO.print("Pleased to meet you, ");
IO.println(name);
}
JEP 513: Flexible Constructor Bodies
JDK22的JEP 447: Statements before super(…) (Preview)作为第一次preview JDK23的JEP 482: Flexible Constructor Bodies (Second Preview)作为第二次preview JDK24的JEP 492: Flexible Constructor Bodies (Third Preview)作为第三次preview JDK25作为正式版本,没有变化
比如在JEP 447之前的代码如下:
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
super(value); // Potentially unnecessary work
if (value <= 0)
throw new IllegalArgumentException(non-positive value);
}
}
在JEP 447之后代码可以如下:
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0)
throw new IllegalArgumentException(non-positive value);
super(value);
}
}
JEP 514: Ahead-of-Time Command-Line Ergonomics
在JDK24的JEP 483: Ahead-of-Time Class Loading & Linking支持了通过Ahead-of-Time Cache来存储已经读取、解析、加载和链接的类 在JDK25则通过简化常见用例所需的命令来加速java应用程序的启动。
在JDK24时分两步创建AOT缓存:
- 首先运行application来记录AOT配置:
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar com.example.App ...
- 接着使用该配置来创建AOT缓存:
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -cp app.jar
- 最后使用AOT缓存启动:
java -XX:AOTCache=app.aot -cp app.jar com.example.App ...
>AOT缓存将读取、解析、加载和链接(通常在程序执行期间即时完成)的任务提前到缓存创建的早期阶段。因此,在执行阶段,程序启动速度更快,因为其类可以从缓存中快速访问。其性能提升可以高达 42%。 >但是需要运行2次来创建AOT缓存。留下AOT配置文件也很不方便,它只是一个临时文件,生产运行不需要,可以删除。
JDK25通过引入AOTCacheOutput
将两步合为一步,它实际上将其调用拆分为两个子调用: 第一个执行训练运行 (AOTMode=record),然后第二个创建AOT缓存 (AOTMode=create),可以通过新的环境变量JDK_AOT_VM_OPTIONS来覆盖传递给cache create这个子过程的VM命令。
java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...
>当以这种方式操作时,JVM为AOT配置创建临时文件,并在完成时删除该文件。
使用的时候一样:
java -XX:AOTCache=app.aot -cp app.jar com.example.App ...
JEP 515: Ahead-of-Time Method Profiling
在JDK24的JEP 483: Ahead-of-Time Class Loading & Linking支持了通过Ahead-of-Time Cache来存储已经读取、解析、加载和链接的类 JVM可以识别执行最频繁或消耗最多CPU时间的代码,并通过将其编译为本机代码来优化此代码。此过程称为分析。简单来说,配置文件是与方法相关的有用信息的集合,例如已执行的次数。当应用程序以通常的方式 (没有AOT缓存) 运行时,这些配置文件在应用程序执行开始时收集。这个JEP背后的概念是,我们可以在训练运行期间收集配置文件,然后在后续运行中重复使用它们。这意味着在以后的执行中,无需在启动后收集配置文件,从而可以立即开始代码编译。训练运行的质量会显着影响应用程序预热时间的改善。训练跑得越好,在随后的跑中获得的性能增强就越大。 本特性将生产环境做的Method Profiling挪到了Ahead-of-Time Cache阶段,使得生产环境启动的时候就读取这些数据,JIT立即对真正的热点方法进行编译,无需边跑边收集。
JEP 518: JFR Cooperative Sampling
本特性提高JFR异步采样Java线程堆栈时的稳定性,通过仅在安全点处遍历调用堆栈来实现此目的,同时最大程度地减少安全点偏差。
JEP 519: Compact Object Headers
在JDK24的JEP 450: Compact Object Headers (Experimental)特性中,在64位架构上,将 HotSpot JVM中的对象标头大小从96到128位减少到64位。在SPECjbb2015的测试中减少了22%的堆空间和8%的CPU时间,完成的垃圾收集数量为减少15%,一个高度并行的JSON解析器基准运行时间减少10%。 在JDK25转为正式版,无需-XX:+UnlockExperimentalVMOptions
命令
-XX:+UseCompactObjectHeaders
JEP 520: JFR Method Timing & Tracing
本特性引入了两个新的JFR事件,jdk.MethodTiming和jdk.MethodTrace,通过字节码织入来追踪方法 使用示例
$ java -XX:StartFlightRecording:jdk.MethodTrace#filter=java.util.HashMap::resize,filename=recording.jfr ...
$ jfr print --events jdk.MethodTrace --stack-depth 20 recording.jfr
jdk.MethodTrace {
startTime = 00:39:26.379 (2025-03-05)
duration = 0.00113 ms
method = java.util.HashMap.resize()
eventThread = "main" (javaThreadId = 3)
stackTrace = [
java.util.HashMap.putVal(int, Object, Object, boolean, boolean) line: 636
java.util.HashMap.put(Object, Object) line: 619
sun.awt.AppContext.put(Object, Object) line: 598
sun.awt.AppContext.<init>(ThreadGroup) line: 240
sun.awt.SunToolkit.createNewAppContext(ThreadGroup) line: 282
sun.awt.AppContext.initMainAppContext() line: 260
sun.awt.AppContext.getAppContext() line: 295
sun.awt.SunToolkit.getSystemEventQueueImplPP() line: 1024
sun.awt.SunToolkit.getSystemEventQueueImpl() line: 1019
java.awt.Toolkit.getEventQueue() line: 1375
java.awt.EventQueue.invokeLater(Runnable) line: 1257
javax.swing.SwingUtilities.invokeLater(Runnable) line: 1415
java2d.J2Ddemo.main(String[]) line: 674
]
}
JEP 521: Generational Shenandoah
在JDK24的JEP 404: Generational Shenandoah (Experimental)提供了一个实验性的分代模式,与其他分代收集器一样分为年轻代和年老代 在JDK25转为正式版本,不再需要-XX:+UnlockExperimentalVMOptions
命令
-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
细项解读
上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 25 Release Notes,这里举几个例子。
添加项
-
Support for reading all remaining characters from a Reader (JDK-8354724) >java.io.Reader新增了方法readAllAsString可以读取剩余字符到String,新增readAllLines读取剩余字符到
List<string>
-
New connectionLabel Method in java.net.http.HttpResponse to Identify Connections (JDK-8350279) >对HttpResponse新增了connectionLabel方法用于关联connection
-
New Property to Construct ZIP FileSystem as Read-only (JDK-8350880) >新增readOnly支持FileSystems.newFileSystem(pathToZipFile, Map.of(“accessMode”,”readOnly”))
-
Updates to ForkJoinPool and CompletableFuture (JDK-8319447) >ForkJoinPool做了更新以实现ScheduledExecutorService,新增了submitWithTimeout方法支持timeout参数
-
Thread Dumps Generated by HotSpotDiagnosticMXBean.dumpThreads and jcmd Thread.dump_to_file Updated to Include Lock Information (JDK-8356870) >com.sun.management.HotSpotDiagnosticMXBean.dumpThreads以及jcmd
Thread.dump_to_file生成的线程堆栈现在包含了锁信息 -
G1 Reduces Remembered Set Overhead by Grouping Regions into Shared Card Sets (JDK-8343782) >以前每个Region都维护自己的G1CardSet,导致内存占用高,新设计在 Remark 阶段之后,把预计会一起被清空的Region归为一组,并分配同一个共享的G1CardSet,省去了它们之间逐一跟踪引用的开销。
移除项
-
java.net.Socket Constructors Can No Longer Be Used to Create a Datagram Socket (JDK-8356154) >java.net.Socket废弃了两个构造器,不再支持创建datagram sockets,需要改为java.net.DatagramSocket替代
-
Removal of PerfData Sampling (JDK-8241678) >-XX:PerfDataSamplingInterval这个被移除了
废弃项
-
Deprecate the Use of java.locale.useOldISOCodes System Property (JDK-8353118) >java.locale.useOldISOCodes这个属性被废弃了
-
The UseCompressedClassPointers Option is Deprecated (JDK-8350753) >UseCompressedClassPointers这个参数被废弃了,接下来将默认开启压缩类指针
-
Various Permission Classes Deprecated for Removal (JDK-8348967, JDK-8353641, JDK-8353642, JDK-8353856, JDK-8347985, JDK-8351224, JDK-8351310) 以下这些Permission相关的类被标记废弃
java.security.UnresolvedPermission
javax.net.ssl.SSLPermission
javax.security.auth.AuthPermission
javax.security.auth.PrivateCredentialPermission
javax.security.auth.kerberos.DelegationPermission
javax.security.auth.kerberos.ServicePermission
com.sun.security.jgss.InquireSecContextPermission
java.lang.RuntimePermission
java.lang.reflect.ReflectPermission
java.io.FilePermission
java.io.SerializablePermission
java.nio.file.LinkPermission
java.util.logging.LoggingPermission
java.util.PropertyPermission
jdk.jfr.FlightRecorderPermission
java.net.NetPermission
java.net.URLPermission
jdk.net.NetworkPermission
com.sun.tools.attach.AttachPermission
com.sun.jdi.JDIPermission
java.lang.management.ManagementPermission
javax.management.MBeanPermission
javax.management.MBeanTrustPermission
javax.management.MBeanServerPermission
javax.management.remote.SubjectDelegationPermission
已知问题修复
-
ZGC Now Avoids String Deduplication for Short-Lived Strings (JDK-8347337) >ZGC将避免对一些生命周期短的String进行Deduplication,避免不必要的开销
-
G1 Reduces Pause Time Spikes by Improving Region Selection (JDK-8351405) >G1在Mixed GC的时候会引起pause time飙升,此次通过region选择进行了优化
-
No More OutOfMemoryErrors Due to JNI in Serial/Parallel GC (JDK-8192647) >修复了Serial/Parallel GC因为JNI导致的OOM
已知问题
-
Regression in Serialization of LocalDate Class Objects (JDK-8367031) 在 java.time 包中,若干类的序列化 Class 对象在 JDK 25 与早期版本之间不再兼容。受影响的具体类包括:LocalDate、YearMonth、MonthDay、HijrahDate 兼容性规则:如果把上述某个类的Class对象在早期版本序列化,再到 JDK 25 反序列化,或者反向操作,都会抛出 InvalidClassException,例如
writeObject(LocalDate.class)
但如果是序列化实例,则不受影响writeObject(LocalDate.now())
-
Performance Regression in java.lang.ClassValue::get (JDK-8358535) 在 JDK 25 中,为了增强 ClassValue 在各种并发场景下的健壮性,JDK-8351996 对其进行了更新。 然而,这次改动导致:在调用 ClassValue.remove 之后,ClassValue.get 的执行速度明显变慢。
- 大多数应用不会直接使用 ClassValue,因此不会感知到这一退化。
- 但若某个库同时调用 ClassValue.get 与 remove(例如 Scala 2.12 的标准库),就可能受到性能影响。 该性能回退已在 JDK-8358535 中被修复。
-
-XX:+UseTransparentHugePages Fails to Enable Huge Pages for G1 (JDK-8366434) 在把Transparent Huge Pages(THP)模式设置为 madvise 的系统上, 即使启动参数里加了 -XX:+UseTransparentHugePages,默认垃圾回收器 G1 也不会实际启用大页。临时解决办法:把 THP 模式改成 always,即可让 G1 正常使用Transparent Huge Pages: