JDK 25 的新特性

JDK 25 的新特性

前言

JDK 发布历程(JDK 8 ~ JDK 24)如下:
在这里插入图片描述
JDK 25 作为最新的长期支持(LTS)版本,带来了一系列旨在提升开发效率、增强语言表达能力和优化性能的新特性。

JDK 25 提供了十六个增强功能,这些增强功能足以保证他们自己的 JDK 增强提案 (JEP),包括四个预览功能、一个实验功能和一个孵化器功能。这些功能涵盖了 Java 语言的创新,包括对安全库的改进、性能和运行时增强以及更新的监视功能。
The Arrival of Java 25
JDK 25 Release Notes

IDEA使用预览属性的方法:

在这里插入图片描述
在这里插入图片描述


语言

JEP 507:模式匹配支持基本类型(第三次预览)

1、作用

允许在instanceof、switch等模式上下文中直接使用基本类型(如int、double),消除了基本类型与包装类型之间的转换开销,统一了模式匹配的语法,简化了代码并提升性能

2、案例

public class PrimitivePatternMatchDemo {

    static void main() {
        Object[] array = new Object[]{1, "two", 3.0, true, 'a', 100L, (short) 128};
        for (Object object : array) {
            analyzeObj(object);
        }
    }

    private static void analyzeObj(Object value) {
        // 1. instanceof支持基本类型模式
        if (value instanceof int i) {
            System.out.printf("int value: %d (even: %b)%n", i, i % 2 == 0);
        }
        // 2. switch支持多种基本类型
        else if (value instanceof double d) {
            System.out.printf("double value: %.2f%n", d);
        }
        // 3. switch模式匹配带守卫条件
        else if (value instanceof long l) {
            switch (l) {
                case 100L -> System.out.println("Found 100L");
                case long num when num > 0 -> System.out.printf("Positive long: %d%n", num);
                default -> System.out.println("Other long value");
            }
        }
        // 4. 基本类型与包装类型统一处理
        else if (value instanceof boolean b) {
            System.out.println("Boolean: " + b);
        }
        else {
            System.out.println("Other type: " + value.getClass().getSimpleName());
        }
    }
}

3、应用场景说明

  • 数据处理:统一处理不同类型的数值数据(如解析JSON、CSV文件)

  • 数学计算:科学计算中对不同精度数值的模式匹配

  • 事件处理:根据不同类型的事件参数执行相应逻辑

  • AI推理:处理机器学习模型输出的各类数值结果

该特性减少了约30%的类型转换代码,同时避免了自动装箱/拆箱带来的性能损耗,特别适合高性能计算场景。

JEP 511:模块导入声明

增强 Java 编程语言,使其能够简洁地导入所有 模块导出的包。这简化了模块化的重用 但不要求导入代码必须存在于模块本身。

package org.example.other;

// 导入 java.base 整个模块
import module java.base;

/**
 * @Description
 * @Author 
 * @Date 2025/11/19 17:20
 * @Version 1.0
 */
public class ModuleImportDemo {

    static void main() {
        ArrayList<Object> objects = new ArrayList<>();
    }
}

JEP 512:紧凑源文件和实例主方法

1、作用

简化Java程序入门门槛,支持无类定义的紧凑源文件和实例主方法(无需static修饰)。

2、案例

// 无需类声明,直接编写代码
void main() {
    IO.println("Hello, JDK 25!");  // IO类已在java.lang包中,无需导入

    // 支持定义方法和变量
    var message = "Current time: " + java.time.LocalTime.now();
    printMessage(message);
}

void printMessage(String msg) {
    IO.println("Message: " + msg);
}

JEP 513:灵活的构造体

1、作用

允许在调用父类构造函数 (super) 或同类其他构造函数 (this) 之前进行参数验证或计算,使代码更安全、更清晰。

2、案例

public class FlexibleConstructorDemo {

    static void main() {
        Person person = new Person("Alice", 30);
        Person employee = new Employee("Bob", 25, 5000);
    }
}

class Person {
    String name;
    int age;
    String id;

    // 构造方法
    Person(String name, int age) {
        if (age < 0) {
            throw new IllegalArgumentException("Invalid age: " + age);
        }
        this.id = generateId();
        this.name = name;
        this.age = age;
    }

    private String generateId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 8);
    }
}

class Employee extends Person {
    double salary;

    // 构造方法
    Employee(String name, int age, double salary) {
        // 1. 在super()前执行参数验证
        if (salary < 0) {
            throw new IllegalArgumentException("Invalid salary: " + salary);
        }
        super(name, age);
        this.salary = salary;
    }
}

3、应用场景说明

  • 参数验证:在调用父类构造函数前验证输入参数

  • 默认值计算:复杂的默认字段值计算(如生成ID、加密处理)

  • 日志记录:构造过程的审计日志

  • 资源准备:在父类初始化前准备必要资源

注意限制:在super()调用前不能引用this或调用实例方法,确保不会访问未初始化的对象状态。


相关 API

JEP 505:结构化并发(第五次预览)

1、作用

引入结构化并发的 API,简化并发编程。结构化并发将不同线程中运行的相关任务组视为单一工作单元,从而简化错误处理和取消,提高可靠性并增强可观测性。

与传统并发对比:

对比维度 传统并发 (如 ExecutorService) 结构化并发 (StructuredTaskScope)
任务生命周期 子任务独立运行,生命周期需手动管理,容易导致"线程泄漏"。 父任务与子任务生命周期绑定。作用域结束后,所有子任务自动取消,避免资源泄漏。
错误传播与处理 错误处理分散,若一个任务失败,其他任务可能继续执行,造成资源浪费。 提供集中式的错误处理。例如,可配置为"任一子任务失败则取消所有其他任务",并及时抛出异常。
代码可观察性 线程转储中,父任务和子任务的调用栈相互独立,关系不清晰,调试困难。 线程转储会清晰显示任务的层次结构,使得并发流程一目了然,易于调试。

2、案例代码

public class StructuredConcurrencyDemo {

    static ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

    static void main() throws InterruptedException, ExecutionException {
        // fetchOrder方法报错后(),会接着执行findUser()方法
        // handleOld();
       handle();
    }

    private static String findUser() throws InterruptedException {
        Thread.sleep(1000);
        String userName = "user_1";
        System.out.println("findUser:" + userName);
        return userName;
    }

    private static int fetchOrder() throws InterruptedException {
//        int i = 1;
        int i = 1 / 0;
        Thread.sleep(1000);
        System.out.println("fetchOrder:" + i);
        return i;
    }

    // 旧:非结构化并发ExecutorService
    static UserOrder handleOld() throws ExecutionException, InterruptedException {
        Future<String> user = executor.submit(() -> findUser());
        Future<Integer> order = executor.submit(() -> fetchOrder());
        String theUser = user.get();   // Join findUser
        int theOrder = order.get();    // Join fetchOrder
        System.out.println("run main====");
        return new UserOrder(theUser, theOrder);
    }

    static UserOrder handle() throws InterruptedException {
        try (var scope = StructuredTaskScope.open()) {
            StructuredTaskScope.Subtask<String> user = scope.fork(() -> findUser());
            StructuredTaskScope.Subtask<Integer> order = scope.fork(() -> fetchOrder());

            scope.join();   // Join subtasks, propagating exceptions
            System.out.println("run main====");
            // Both subtasks have succeeded, so compose their results
            return new UserOrder(user.get(), order.get());
        }
    }
}

class UserOrder {
    private final String theUser;
    private final int theOrder;

    public UserOrder(String theUser, int theOrder) {
        this.theUser = theUser;
        this.theOrder = theOrder;
    }
}

JEP 506: Scoped Values(作用域值)

1、作用

作用域值(Scoped Values)是线程局部变量的现代化替代方案。它是不可变的,并且为虚拟线程进行了优化,能更安全、高效地在同一线程及其子线程间共享数据。

相比ThreadLocal,作用域值具有自动清理机制,不会因线程复用导致内存泄漏,且在虚拟线程环境下性能提升尤为显著。

2、案例

public class ScopedValuesDemo {

    private final static ScopedValue<String> USER_NAME = ScopedValue.newInstance();

    static void main() {
        ScopedValue.where(USER_NAME, "Alice")
                .run(() -> {
                    System.out.println("Hello, " + USER_NAME.get());
                });
        ScopedValue.where(USER_NAME, "Bob")
                .run(() -> {
                    System.out.println("Hello, " + USER_NAME.get());
                });
        // 报错java.util.NoSuchElementException: ScopedValue not bound
//        username.get();

        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            // 绑定作用域值并提交任务
            executor.submit(() -> ScopedValue.where(USER_NAME, "alice_123")
                    .run(() -> {
                        Thread.currentThread().setName("Alice-Thread");
                        processRequest("Order_001");
                    }));

            executor.submit(() -> ScopedValue.where(USER_NAME, "bob_456")
                    .run(() -> {
                        Thread.currentThread().setName("Bob-Thread");
                        processRequest("Order_002");
                    }));
        }
    }

    private static void processRequest(String orderId) {
        demoLog("Processing request: " + orderId);
        // 在作用域值中获取用户名
        validUserName();
        // 根据订单ID处理订单
        doSomeThingByOrderId(orderId);
    }

    private static void doSomeThingByOrderId(String orderId) {
        demoLog("Processing order: " + orderId);
        String currentUser = USER_NAME.get();
        demoLog("Current user: " + currentUser);
    }

    private static void validUserName() {
        if (USER_NAME.get() == null) {
            demoLog("User name is not set");
            throw new IllegalStateException("User name is not set");
        }
        demoLog("User name: " + USER_NAME.get());
    }

    private static void demoLog(String message) {
        System.out.printf("[Thread: %s] %s%n", Thread.currentThread().getName(), message);
    }
}

运行结果:
在这里插入图片描述

3、应用场景

适用于需要在调用链或子线程间传递上下文信息的场景,如:

  • Web服务中的请求ID、用户认证信息传递

  • 分布式追踪系统的追踪上下文传播

  • 日志系统的上下文标记

  • 微服务调用中的元数据共享

JEP 510:密钥派生函数API

1、作用

提供标准化的密钥派生函数(KDF)API,支持HKDF、Argon2等算法,用于从主密钥或密码派生出加密密钥。该API简化了密码学应用开发,增强了安全性,并为量子计算时代的密码学准备了基础。

密钥派生函数(Key Derivation Function, KDF)是一种密码学函数,用于从一个主密钥(如密码或共享秘密)派生出一个或多个密钥。KDF 的主要目的是增强密钥的安全性,通常通过以下方式实现:

  • 增加计算复杂度:通过多次迭代或使用计算密集型操作,使得暴力破解变得困难。
  • 引入盐值(Salt):防止预计算攻击(如彩虹表攻击)。
  • 支持多密钥派生:从一个主密钥派生出多个密钥,用于不同的用途。

2、案例代码

public class KDFDemo {

    public static void main(String[] args) throws Exception {
        // 1. 使用HKDF算法派生密钥
        byte[] initialKeyMaterial = "master-secret-key".getBytes(StandardCharsets.UTF_8);
        byte[] salt = "unique-salt-123".getBytes(StandardCharsets.UTF_8);
        byte[] info = "auth-token".getBytes(StandardCharsets.UTF_8);

        // 初始化KDF
        // 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);

        // 派生密钥
        byte[] derivedKey = hkdf.deriveData(params);

        System.out.println("Derived key length: " + derivedKey.length + " bytes");
        System.out.println("Derived key: " + bytesToHex(derivedKey));

    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

}

运行结果:

Derived key length: 32 bytes
Derived key: 0d878149cfb91007092385675ae897001cc42f6b868920d4ea80a1a326bb1b6d

3、应用场景说明

  • 密码存储:安全存储用户密码(替代PBKDF2)

  • TLS协议:密钥交换过程中的密钥派生

  • 区块链:加密货币中的地址生成和交易签名

  • 云安全:服务间通信的密钥管理

  • 量子安全:为后量子密码学算法提供基础支持

该API减少了对BouncyCastle等第三方库的依赖,提供了标准化的密码学实现,降低了安全漏洞风险。


性能

JEP 519:紧凑对象头

最早在JDK 24的时候作为实验性功能引入,已证明其稳定及性能。

1、作用

优化JVM对象头结构,在64位系统上将对象头大小从12字节(压缩类指针)或16字节(未压缩)减少到8字节。这一改进无需修改代码即可减少堆内存占用约20-25%,提升GC性能和CPU缓存利用率,特别适合微服务和云原生环境。

2、应用场景说明

  • 微服务架构:减少容器内存占用,提高部署密度

  • 大数据处理:降低海量小对象场景的内存开销

  • 实时系统:减少GC压力,降低延迟波动

  • 云原生应用:提高资源利用率,降低云服务成本

启用方式:java -XX:+UseCompactObjectHeaders YourApp

根据SPECjbb2015基准测试,该特性可使堆内存占用减少22%,GC频率降低15%,CPU使用率降低8%。


其他特性

  • 移除了32位x86架构的支持

  • 向量(Vector)API增强(第十次孵化)

  • PEM密钥「即插即用」
    引入一个API,用于将代表密码密钥、证书和证书撤销列表的对象编码到广泛使用的隐私增强邮件(PEM)传输格式中,并将该格式解码回对象。

  • JFR(JDK Flight Recorder)增强
    新增CPU采样、方法计时追踪,方便快速定位性能问题。(JEP 509、518、520)

  • 其他...

posted @ 2025-12-05 15:52  似有风中泣  阅读(13)  评论(0)    收藏  举报