Java25的新特性

Java語(yǔ)言特性系列

本文主要講述一下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替代

-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。

此次發(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java語(yǔ)言特性系列 Java5的新特性[https://segmentfault.com/a/119000000...
    go4it閱讀 1,119評(píng)論 0 1
  • Java語(yǔ)言特性系列 Java5的新特性[https://segmentfault.com/a/119000000...
    go4it閱讀 386評(píng)論 0 3
  • Java語(yǔ)言特性系列 Java5的新特性[https://segmentfault.com/a/119000000...
    go4it閱讀 1,816評(píng)論 1 2
  • 序 本文主要講述一下Java23的新特性 版本號(hào) 從version信息可以看出是build 23+37 特性列表 ...
    go4it閱讀 275評(píng)論 0 0
  • 有的時(shí)候博客內(nèi)容會(huì)有變動(dòng),首發(fā)博客是最新的,其他博客地址可能會(huì)未同步,認(rèn)準(zhǔn)https://blog.zysicyj...
    njpkhuan閱讀 363評(píng)論 0 0

友情鏈接更多精彩內(nèi)容