Java語(yǔ)言特性系列
- Java5的新特性
- Java6的新特性
- Java7的新特性
- Java8的新特性
- Java9的新特性
- Java10的新特性
- Java11的新特性
- Java12的新特性
- Java13的新特性
- Java14的新特性
- Java15的新特性
- Java16的新特性
- Java17的新特性
- Java18的新特性
- Java19的新特性
- Java20的新特性
- Java21的新特性
- Java22的新特性
- Java23的新特性
- Java24的新特性
- Java25的新特性
- Java26的新特性
序
本文主要講述一下Java25的新特性
版本號(hào)
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平臺(tái)引入了一套簡(jiǎn)潔、易用且線程安全的API(Preview版本),用于在 PEM(Privacy-Enhanced Mail)文本與各類密碼學(xué)對(duì)象(密鑰、證書、CRL 等)之間進(jìn)行雙向轉(zhuǎn)換,解決開發(fā)者長(zhǎng)期需要手寫解析/格式化邏輯的痛點(diǎn)。
DEREncodable 標(biāo)記接口
統(tǒng)一標(biāo)識(shí)可參與 PEM 編解碼的已有類型:
AsymmetricKey、X509Certificate、X509CRL、KeyPair、EncryptedPrivateKeyInfo、PKCS8EncodedKeySpec、X509EncodedKeySpec 以及新引入的 PEMRecord。PEMEncoder / PEMDecoder
不可變、可復(fù)用、線程安全。
支持直接編解碼字符串或字節(jié)流,提供 encode(DerEncodable) / decode(String/InputStream) 等便捷方法。
通過 withEncryption(char[] password) / withDecryption(...) 一鍵加解密私鑰;默認(rèn)算法可在安全屬性文件中配置(當(dāng)前為 PBEWithHmacSHA256AndAES_128)。
通過 withFactory(Provider) 可指定特定加密提供者。PEMRecord 記錄類
用于處理平臺(tái)暫無對(duì)應(yīng) API 的 PEM 類型(如 PKCS#10 請(qǐng)求)或需要保留 PEM 首部前導(dǎo)數(shù)據(jù)的場(chǎng)景。EncryptedPrivateKeyInfo 增強(qiáng)
新增靜態(tài)工廠方法 encryptKey(...) 與實(shí)例方法 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());
}
}
編譯及運(yùn)行
javac --release 25 --enable-preview PEMEncoding.java
java --enable-preview PEMEncoding
JEP 502: Stable Values (Preview)
本特性引入了一種名為 Stable Values(穩(wěn)定值) 的 API,用于支持延遲初始化的不可變數(shù)據(jù)持有者對(duì)象。這一特性在 JDK 25 中以預(yù)覽功能形式提供,旨在提升 Java 應(yīng)用的啟動(dòng)性能與并發(fā)安全性,同時(shí)保留 final 字段的優(yōu)化能力(如常量折疊)。 Stable Values填補(bǔ)了final字段與可變字段之間的空白,在保持不可變性和線程安全的同時(shí),支持按需初始化,特別適用于啟動(dòng)時(shí)需要延遲加載資源的大型應(yīng)用場(chǎng)景。
使用示例如下:
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");
}
}
由于是預(yù)覽版本,所以需要--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已經(jīng)廢棄了對(duì)Windows 32位 x86的移植
在JDK24的JEP 479: Remove the Windows 32-bit x86 Port刪除了相關(guān)源代碼、移除了對(duì)windows 32位相關(guān)構(gòu)建支持
在JDK24的JEP 501: Deprecate the 32-bit x86 Port for Removal廢棄了對(duì)32位x86的移植,但是可以通過--enable-deprecated-ports=yes來啟用構(gòu)建
在JDK25Z則刪除了相關(guān)源代碼、移除了相關(guān)構(gòu)建支持
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()再鏈?zhǔn)秸{(diào)用run(Runnable)或者call(Callable)
JDK25作為第五次preview,有個(gè)改動(dòng)就是ScopedValue.orElse方法不再接受null作為參數(shù)
示例:
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) 中,框架聲明了一個(gè)作用域值,而不是一個(gè)thread local變量。在 (2),serve方法調(diào)用where ... run而不是thread local的set方法。run方法提供了數(shù)據(jù)的單向共享serve方法到readKey方法。(3) 讀取的值是由Framework.serve的時(shí)候?qū)懭氲摹?/p>
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模式匹配正式發(fā)布
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);
}
}
但是這個(gè)只是支持Record類型
在JDK14JEP 305: Pattern Matching for instanceof (Preview)作為preview
在JDK15JEP 375: Pattern Matching for instanceof (Second Preview)作為第二輪的preview
在JDK16JEP 394: Pattern Matching for instanceof轉(zhuǎn)正
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作為正式版本發(fā)布,示例如下
// 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
}
另外針對(duì)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來用于矢量計(jì)算
JDK17進(jìn)行改進(jìn)并作為第二輪的incubatorJEP 414: Vector API (Second Incubator)
JDK18的JEP 417: Vector API (Third Incubator)進(jìn)行改進(jìn)并作為第三輪的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相比做了一些變動(dòng):比如引入了一個(gè)新的基于值的類Float16,用于表示IEEE 754二進(jìn)制16格式的16位浮點(diǎn)數(shù)。
JDK25作為第十輪incubator,主要變化是:VectorShuffle現(xiàn)在支持訪問和訪問MemorySegment,該實(shí)現(xiàn)是通過Foreign Function & Memory API (JEP 454) 而不是通過HotSpot內(nèi)部的C++代碼,提高了可維護(hù)性,另外對(duì)Float16值的加法、減法、除法、乘法、平方根和fused乘法/加法運(yùn)算現(xiàn)在支持x64 cpu自動(dòng)矢量化
JEP 509: JFR CPU-Time Profiling (Experimental)
本特性引入了實(shí)驗(yàn)版的CPU-Time Profiling,可以捕獲更準(zhǔn)確的CPU時(shí)間分析信息
使用示例
$ 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的一個(gè)組成部分,標(biāo)志著Java朝著HPKE邁出的第一步,并為后量子挑戰(zhàn)做好了準(zhǔn)備。
在JDK24的JEP 478: Key Derivation Function API (Preview)中提出了HPKE的另一個(gè)組成部分,作為這一方向上的下一步:密鑰派生函數(shù)(KDFs)的API,作為預(yù)覽版本
在JDK25轉(zhuǎn)為正式版,無需--enable-preview參數(shù)
使用示例如下:
// 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)類似,本特性主要是為了簡(jiǎn)化語(yǔ)法方便新手使用,通過新引入module的import,來一次性導(dǎo)入module下所有package底下的類
JDK23的JEP 476: Module Import Declarations (Preview)作為第一個(gè)preview
JDK24的JEP 494: Module Import Declarations (Second Preview)作為第二次preview,與JDK23不同的是取消了模塊不允許聲明對(duì)java.base模塊傳遞依賴的限制,并修訂了java.se模塊聲明,使其傳遞性地依賴于java.base模塊。這些變化意味著導(dǎo)入java.se模塊將按需導(dǎo)入整個(gè)Java SE API。此外,現(xiàn)在允許按需聲明的類型導(dǎo)入聲明覆蓋模塊導(dǎo)入聲明。
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參數(shù)來開啟
JEP 512: Compact Source Files and Instance Main Methods
JDK21的JEP 445: Unnamed Classes and Instance Main Methods (Preview)作為首次preview,引入了未命名的類和實(shí)例main方法特性可以簡(jiǎn)化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作為正式版本,有些改動(dòng):
- console I/O的新IO類現(xiàn)在位于java.lang,而不是java.io包,現(xiàn)在隱式導(dǎo)入到每個(gè)源文件
- IO類的靜態(tài)方法不再隱式導(dǎo)入compact source files,需要顯示導(dǎo)入
- IO類的實(shí)現(xiàn)基于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來存儲(chǔ)已經(jīng)讀取、解析、加載和鏈接的類
在JDK25則通過簡(jiǎn)化常見用例所需的命令來加速java應(yīng)用程序的啟動(dòng)。
在JDK24時(shí)分兩步創(chuàng)建AOT緩存:
- 首先運(yùn)行application來記錄AOT配置:
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar com.example.App ...
- 接著使用該配置來創(chuàng)建AOT緩存:
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot -cp app.jar
- 最后使用AOT緩存啟動(dòng):
java -XX:AOTCache=app.aot -cp app.jar com.example.App ...
AOT緩存將讀取、解析、加載和鏈接(通常在程序執(zhí)行期間即時(shí)完成)的任務(wù)提前到緩存創(chuàng)建的早期階段。因此,在執(zhí)行階段,程序啟動(dòng)速度更快,因?yàn)槠漕惪梢詮木彺嬷锌焖僭L問。其性能提升可以高達(dá) 42%。
但是需要運(yùn)行2次來創(chuàng)建AOT緩存。留下AOT配置文件也很不方便,它只是一個(gè)臨時(shí)文件,生產(chǎn)運(yùn)行不需要,可以刪除。
JDK25通過引入AOTCacheOutput將兩步合為一步,它實(shí)際上將其調(diào)用拆分為兩個(gè)子調(diào)用: 第一個(gè)執(zhí)行訓(xùn)練運(yùn)行 (AOTMode=record),然后第二個(gè)創(chuàng)建AOT緩存 (AOTMode=create),可以通過新的環(huán)境變量JDK_AOT_VM_OPTIONS來覆蓋傳遞給cache create這個(gè)子過程的VM命令。
java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ...
當(dāng)以這種方式操作時(shí),JVM為AOT配置創(chuàng)建臨時(shí)文件,并在完成時(shí)刪除該文件。
使用的時(shí)候一樣:
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來存儲(chǔ)已經(jīng)讀取、解析、加載和鏈接的類
JVM可以識(shí)別執(zhí)行最頻繁或消耗最多CPU時(shí)間的代碼,并通過將其編譯為本機(jī)代碼來優(yōu)化此代碼。此過程稱為分析。簡(jiǎn)單來說,配置文件是與方法相關(guān)的有用信息的集合,例如已執(zhí)行的次數(shù)。當(dāng)應(yīng)用程序以通常的方式 (沒有AOT緩存) 運(yùn)行時(shí),這些配置文件在應(yīng)用程序執(zhí)行開始時(shí)收集。這個(gè)JEP背后的概念是,我們可以在訓(xùn)練運(yùn)行期間收集配置文件,然后在后續(xù)運(yùn)行中重復(fù)使用它們。這意味著在以后的執(zhí)行中,無需在啟動(dòng)后收集配置文件,從而可以立即開始代碼編譯。訓(xùn)練運(yùn)行的質(zhì)量會(huì)顯著影響應(yīng)用程序預(yù)熱時(shí)間的改善。訓(xùn)練跑得越好,在隨后的跑中獲得的性能增強(qiáng)就越大。
本特性將生產(chǎn)環(huán)境做的Method Profiling挪到了Ahead-of-Time Cache階段,使得生產(chǎn)環(huán)境啟動(dòng)的時(shí)候就讀取這些數(shù)據(jù),JIT立即對(duì)真正的熱點(diǎn)方法進(jìn)行編譯,無需邊跑邊收集。
JEP 518: JFR Cooperative Sampling
本特性提高JFR異步采樣Java線程堆棧時(shí)的穩(wěn)定性,通過僅在安全點(diǎn)處遍歷調(diào)用堆棧來實(shí)現(xiàn)此目的,同時(shí)最大程度地減少安全點(diǎn)偏差。
JEP 519: Compact Object Headers
在JDK24的JEP 450: Compact Object Headers (Experimental)特性中,在64位架構(gòu)上,將 HotSpot JVM中的對(duì)象標(biāo)頭大小從96到128位減少到64位。在SPECjbb2015的測(cè)試中減少了22%的堆空間和8%的CPU時(shí)間,完成的垃圾收集數(shù)量為減少15%,一個(gè)高度并行的JSON解析器基準(zhǔn)運(yùn)行時(shí)間減少10%。
在JDK25轉(zhuǎn)為正式版,無需-XX:+UnlockExperimentalVMOptions命令
-XX:+UseCompactObjectHeaders
JEP 520: JFR Method Timing & Tracing
本特性引入了兩個(gè)新的JFR事件,jdk.MethodTiming和jdk.MethodTrace,通過字節(jié)碼織入來追蹤方法
使用示例
$ 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)提供了一個(gè)實(shí)驗(yàn)性的分代模式,與其他分代收集器一樣分為年輕代和年老代
在JDK25轉(zhuǎn)為正式版本,不再需要-XX:+UnlockExperimentalVMOptions命令
-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
細(xì)項(xiàng)解讀
上面列出的是大方面的特性,除此之外還有一些api的更新及廢棄,主要見JDK 25 Release Notes,這里舉幾個(gè)例子。
添加項(xiàng)
- 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)
對(duì)HttpResponse新增了connectionLabel方法用于關(guān)聯(lián)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做了更新以實(shí)現(xiàn)ScheduledExecutorService,新增了submitWithTimeout方法支持timeout參數(shù)
- 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 <pid> Thread.dump_to_file生成的線程堆?,F(xiàn)在包含了鎖信息
- G1 Reduces Remembered Set Overhead by Grouping Regions into Shared Card Sets (JDK-8343782)
以前每個(gè)Region都維護(hù)自己的G1CardSet,導(dǎo)致內(nèi)存占用高,新設(shè)計(jì)在 Remark 階段之后,把預(yù)計(jì)會(huì)一起被清空的Region歸為一組,并分配同一個(gè)共享的G1CardSet,省去了它們之間逐一跟蹤引用的開銷。
移除項(xiàng)
- java.net.Socket Constructors Can No Longer Be Used to Create a Datagram Socket (JDK-8356154)
java.net.Socket廢棄了兩個(gè)構(gòu)造器,不再支持創(chuàng)建datagram sockets,需要改為java.net.DatagramSocket替代
- Removal of PerfData Sampling (JDK-8241678)
-XX:PerfDataSamplingInterval這個(gè)被移除了
廢棄項(xiàng)
- Deprecate the Use of java.locale.useOldISOCodes System Property (JDK-8353118)
java.locale.useOldISOCodes這個(gè)屬性被廢棄了
- The UseCompressedClassPointers Option is Deprecated (JDK-8350753)
UseCompressedClassPointers這個(gè)參數(shù)被廢棄了,接下來將默認(rèn)開啟壓縮類指針
- Various Permission Classes Deprecated for Removal (JDK-8348967, JDK-8353641, JDK-8353642, JDK-8353856, JDK-8347985, JDK-8351224, JDK-8351310)
以下這些Permission相關(guān)的類被標(biāo)記廢棄
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
已知問題修復(fù)
- ZGC Now Avoids String Deduplication for Short-Lived Strings (JDK-8347337)
ZGC將避免對(duì)一些生命周期短的String進(jìn)行Deduplication,避免不必要的開銷
- G1 Reduces Pause Time Spikes by Improving Region Selection (JDK-8351405)
G1在Mixed GC的時(shí)候會(huì)引起pause time飆升,此次通過region選擇進(jìn)行了優(yōu)化
- No More OutOfMemoryErrors Due to JNI in Serial/Parallel GC (JDK-8192647)
修復(fù)了Serial/Parallel GC因?yàn)镴NI導(dǎo)致的OOM
已知問題
Regression in Serialization of LocalDate Class Objects (JDK-8367031)
在 java.time 包中,若干類的序列化 Class 對(duì)象在 JDK 25 與早期版本之間不再兼容。受影響的具體類包括:LocalDate、YearMonth、MonthDay、HijrahDate
兼容性規(guī)則:如果把上述某個(gè)類的Class對(duì)象在早期版本序列化,再到 JDK 25 反序列化,或者反向操作,都會(huì)拋出 InvalidClassException,例如writeObject(LocalDate.class)
但如果是序列化實(shí)例,則不受影響writeObject(LocalDate.now())-
Performance Regression in java.lang.ClassValue::get (JDK-8358535)
在 JDK 25 中,為了增強(qiáng) ClassValue 在各種并發(fā)場(chǎng)景下的健壯性,JDK-8351996 對(duì)其進(jìn)行了更新。
然而,這次改動(dòng)導(dǎo)致:在調(diào)用 ClassValue.remove 之后,ClassValue.get 的執(zhí)行速度明顯變慢。- 大多數(shù)應(yīng)用不會(huì)直接使用 ClassValue,因此不會(huì)感知到這一退化。
- 但若某個(gè)庫(kù)同時(shí)調(diào)用 ClassValue.get 與 remove(例如 Scala 2.12 的標(biāo)準(zhǔn)庫(kù)),就可能受到性能影響。
該性能回退已在 JDK-8358535 中被修復(fù)。
-XX:+UseTransparentHugePages Fails to Enable Huge Pages for G1 (JDK-8366434)
在把Transparent Huge Pages(THP)模式設(shè)置為 madvise 的系統(tǒng)上,
即使啟動(dòng)參數(shù)里加了 -XX:+UseTransparentHugePages,默認(rèn)垃圾回收器 G1 也不會(huì)實(shí)際啟用大頁(yè)。臨時(shí)解決辦法:把 THP 模式改成 always,即可讓 G1 正常使用Transparent Huge Pages:
# echo always > /sys/kernel/mm/transparent_hugepage/enabled
其他事項(xiàng)
- Disabled SHA-1 in TLS 1.2 and DTLS 1.2 Handshake Signatures (JDK-8340321)
- Compact Object Headers CDS Archive Generation and jlink Instruction (JDK-8350457)
小結(jié)
Java25主要有如下幾個(gè)特性,其中核心庫(kù)改動(dòng)有JEP 502、JEP 505、JEP 506、JEP 508,語(yǔ)言規(guī)范類的有JEP507、JEP 511、JEP 512、JEP 513。
- JEP 470: PEM Encodings of Cryptographic Objects (Preview)
- JEP 502: Stable Values (Preview)
- JEP 503: Remove the 32-bit x86 Port
- JEP 505: Structured Concurrency (Fifth Preview)
- JEP 506: Scoped Values
- JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
- JEP 508: Vector API (Tenth Incubator)
- JEP 509: JFR CPU-Time Profiling (Experimental)
- JEP 510: Key Derivation Function API
- JEP 511: Module Import Declarations
- JEP 512: Compact Source Files and Instance Main Methods
- JEP 513: Flexible Constructor Bodies
- JEP 514: Ahead-of-Time Command-Line Ergonomics
- JEP 515: Ahead-of-Time Method Profiling
- JEP 518: JFR Cooperative Sampling
- JEP 519: Compact Object Headers
- JEP 520: JFR Method Timing & Tracing
- JEP 521: Generational Shenandoah
此次發(fā)布了18個(gè)JEP,整體概括如下:
| JEP | Title | Status | Project | Feature Type | Changes since Java 24 |
|---|---|---|---|---|---|
| 470 | PEM Encodings of Cryptographic Objects | Preview | Security Libs | Security | New feature |
| 502 | Stable Values | Preview | Core Libs | New API | New feature |
| 503 | Remove the 32-bit x86 Port | HotSpot | Deprecation | Removal | |
| 505 | Structured Concurrency | Fifth Preview | Loom | Concurrency | Major |
| 506 | Scoped Values | Loom | Concurrency | Minor | |
| 507 | Primitive Types in Patterns, instanceof, and switch | Third Preview | Amber | Language | None |
| 508 | Vector API | Tenth Incubator | Panama | New API | Minor |
| 509 | JFR CPU-Time Profiling | Experimental | HotSpot / JFR | Profiling | New feature |
| 510 | Key Derivation Function API | Security Libs | Security | None | |
| 511 | Module Import Declarations | Amber | Language | None | |
| 512 | Compact Source Files and Instance Main Methods | Amber | Language | Major | |
| 513 | Flexible Constructor Bodies | Amber | Language | None | |
| 514 | Ahead-of-Time Command-Line Ergonomics | Leyden | Performance | New feature | |
| 515 | Ahead-of-Time Method Profiling | Leyden | Performance | New feature | |
| 518 | JFR Cooperative Sampling | HotSpot / JFR | Profiling | New feature | |
| 519 | Compact Object Headers | HotSpot | Performance | None | |
| 520 | JFR Method Timing & Tracing | HotSpot / JFR | Profiling | New feature | |
| 521 | Generational Shenandoah | HotSpot / GC | Performance | Stability and performance improvements |
doc
- JDK 25 Features
- JDK 25 Release Notes
- Consolidated JDK 25 Release Notes
- Java SE 25 deprecated-list
- The Arrival of Java 25
- Java 25, the Next LTS Release, Delivers Finalized Features and Focus on Performance and Runtime
- JDK 25 and JDK 26: What We Know So Far
- The Java Version Almanac Java25
- Here’s Java 25, Ready to Perform to the Limit
- What's New in Project Leyden - JEP 514 and JEP 515 Explained