JJDK 25 作为 Java 的下一个长期支持版本(LTS),计划于 2025 年 9 月16日正式发布。该版本聚焦语言表达力提升、性能优化、并发模型革新及安全增强,是继 JDK 21 后的首个 LTS 版本。共18个JEP。

font style="color:rgb(77, 77, 77);"</font>

font style="color:rgb(77, 77, 77);"</font>

1.1 简化main方法​

简化 Java 程序入口,支持无类声明的 void main() 方法,无需 public static 修饰符

新版写法​

// 无需显式类声明
void main() {
    IO.println("Hello, JDK 25!"); // java.lang.IO 自动导入
    String name = IO.readLine("Enter your name: ");
    IO.println("Hello, " + name);
}

老版写法​

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, JDK 8!");
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter your name: ");
        String name = scanner.nextLine();
        System.out.println("Hello, " + name);
    }
}

大幅降低 Java 学习门槛,适合脚本编写和快速原型开发,让初学者能更轻松地编写第一个程序

font style="color:rgb(44, 62, 80);"</font>

1.2灵活的构造函数体​

允许在 super() 或 this() 调用前执行初始化逻辑(如参数校验)

font style="color:rgb(44, 62, 80);"</font>

新版写法​

class User {
    private  int age;
    User(int age) {
        // 初始化前置
        if (age < 18 || age > 67)
            throw new IllegalArgumentException("Age must be between 18 and 67");
        super(); // super() 调用可不再强制首行
    }
}

font style="color:rgb(44, 62, 80);"</font>

老版写法​

class User {
    private  int age;
    User(int age) {
        super(); // 必须为第一行
        // 前置初始化逻辑需移到 super() 之后
        if (age < 18 || age > 67) {
            throw new IllegalArgumentException("Age must be between 18 and 67");
        }
        this.age = age; // 显式赋值
    }
}
  • 确保继承链的初始化顺序:从Object到最终子类,逐层初始化

  • 内存安全:子类使用任何继承的成员前,父类必须完全初始化

  • 防止重复初始化:避免父类构造函数被多次调用

font style="color:rgb(44, 62, 80);"</font>

提升代码可读性和灵活性,避免将校验逻辑提取到静态方法的模板代码,增强对象构建时的安全性

font style="color:rgb(44, 62, 80);"</font>

font style="color:rgb(44, 62, 80);"</font>

1.3 模块一次性导入(预览特性)]​

允许通过 import module 一次性导入模块的所有公共类

 

新版写法​

import module java.base; // 导入 java 模块的所有基础公共类
// 可直接使用 List、ArrayList 等,无需单独导入
void main() {
    List<String> list = new ArrayList<>();
}

[#](#老版写法-2) 老版写法​

import java.util.List;      // 显式导入单个类
import java.util.ArrayList; // 显式导入另一个类
public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        System.out.println(list);
    }
}

[#](#新版优点-2) 新版优点​

减少冗余的导入语句,提升模块化代码的可读性和编写效率,尤其在依赖多模块时非常有用。


1.4 **原始类型模式匹配(预览特性)**​

在 switch 和 instanceof 中直接匹配原始类型,如 int、boolean 等。

[#](#新版写法-3) 新版写法​

static void test(Object obj) {
    if (obj instanceof int i) { // 直接匹配 int 类型
        System.out.println("It's an int: " + i);
    }
}
 int value = 10 ;
        switch (value) {
            case int i -> IO.println("小整数: " + i);
            case float f -> IO.println("浮点数: " + f);
        }

[#](#老版写法-3) 老版写法​

static void test(Object obj) {
    if (obj instanceof Integer) { // 检查是否为 Integer 包装类型
        int i = (int) obj;        // 显式拆箱
        System.out.println("It's an int: " + i);
    }
}

目前模式匹配只能用于引用类型,如果你想在 switch 中匹配基本类型,只能用常量,不能绑定变量。

早期版本 instanceof 仅支持引用类型(如 Integer、String),需依赖装箱/拆箱(Integer → int)。

[#](#新版优点-3) 新版优点​

统一原始类型与引用类型的模式匹配,简化类型判断逻辑,减少样板代码。

[#](#_2-并发编程增强) 2.并发编程增强

[#](#_2-1-作用域值-scoped-values) 2.1 **作用域值(Scoped Values)**​

允许在线程内和跨线程共享不可变数据,旨在替代 ThreadLocal,优化虚拟线程不可变信息的传递。

ThreadLocal 使用场景,在同一个请求内获取用户信息:

public class UserService {
    private static final ThreadLocal<String> USER_ID = new ThreadLocal<>();
    
    public void processRequest(String userId) {
        USER_ID.set(userId);  // 写入
        doWork();
        USER_ID.remove();  // 问题:必须手动清理,容易忘记
    }
    
    public void doWork() {
        String userId = USER_ID.get();  // 读取
        System.out.println("处理用户: " + userId);
        // 问题:其他代码可以随意修改
        USER_ID.set("被篡改的值");
    }
}
  1. 容易内存泄漏:必须手动调用 <font style="color:rgb(31, 35, 40);background-color:rgba(129, 139, 152, 0.12);">remove()</font>

  2. 可以随意修改数据,可能导致不可预期的结果

如果想让子线程也共享数据,每个子线程都要复制一份数据。如果你使用的是 Java 21 的虚拟线程,1000 个虚拟线程就要复制1000 次,性能很差。

font style="color:rgb(31, 35, 40);"</font>

InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
threadLocal.set("用户数据");
for (int i = 0; i < 1000; i++) {
    Thread.ofVirtual().start(() -> {
        String data = threadLocal.get(); // 每个线程都有自己的副本
    });
}

什么是 Scoped Values?​

Scoped Values 允许方法 在线程内以及子线程间安全高效地共享不可变数据

和传统的 ThreadLocal 相比,它不仅更安全,而且在虚拟线程环境下的内存开销要小很多。

Scoped Values 和 ThreadLocal 的写法很像:

font style="color:rgb(31, 35, 40);"</font>

import static java.lang.ScopedValue.where;
public class UserService {
    private static final ScopedValue<String> USER_ID = ScopedValue.newInstance();
    
    public void processRequest(String userId) {
        where(USER_ID, userId)  // 写入并绑定作用域
            .run(this::doWork);
        // 自动清理,无需 remove()
    }
    
    public void doWork() {
        String userId = USER_ID.get();  // 读取
        System.out.println("处理用户: " + userId);
    }
}

用 <font style="color:rgb(31, 35, 40);background-color:rgba(129, 139, 152, 0.12);">where().run()</font> 自动管理作用域,出了作用域就自动清理,更安全。

而且作用域一旦绑定,值就不能被修改,避免意外的状态变更。

font style="color:rgb(31, 35, 40);"</font>

使用方式​

1)支持返回值

除了 <font style="color:rgb(31, 35, 40);background-color:rgba(129, 139, 152, 0.12);">run()</font> 方法,还可以使用 <font style="color:rgb(31, 35, 40);background-color:rgba(129, 139, 152, 0.12);">call()</font> 方法来处理有返回值的场景:

public String processWithResult(String input) {
    return where(CONTEXT, input)
        .call(() -> {
            String processed = doSomeWork();
            return "结果: " + processed;
        });
}

2)嵌套作用域

支持在已有作用域内建立新的嵌套作用域:

void outerMethod() {
    where(X, "hello").run(() -> {
        System.out.println(X.get());  // 输出 "hello"
        where(X, "goodbye").run(() -> {
            System.out.println(X.get());  // 输出 "goodbye"
        });
        System.out.println(X.get());  // 输出 "hello"
    });
}

3)多值绑定

可以在一个调用中绑定多个 Scoped Values,或者直接用类封装多个值:

where(USER_ID, userId)
    .where(REQUEST_ID, requestId)
    .where(TENANT_ID, tenantId)
    .run(() -> {
        processRequest();
    });

4)和结构化并发配合

Scoped Values 和 Java 结构化并发 API 可以打个配合,子线程自动继承父线程的作用域值:

  void handleRequest() {
        where(USER_ID, getCurrentUserId())
                .run(() -> {
                    try (var scope = StructuredTaskScope.open()) {
                        var userTask = scope.fork(() -> loadUser());      // 子线程可以访问 USER_ID
                        var ordersTask = scope.fork(() -> loadOrders());  // 子线程可以访问 USER_ID
                        try {
                            scope.join();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        IO.println(userTask.get());
                        IO.println(ordersTask.get());
                    }
                });
    }

如果要在线程中共享不可变数据、尤其是使用了虚拟线程的场景,建议使用 Scoped Values;但如果线程中共享的数据可能需要更新,那么还是使用 ThreadLocal,要根据实际场景选择

[#](#新版优点-4) 新版优​

不可变性保证线程安全,内存占用比 ThreadLocal 低约 40%,生命周期自动绑定,无内存泄漏风险,尤其适合虚拟线程场景。

[#](#_2-2-结构化并发-预览特性) 2.2 **结构化并发(预览特性)**​

将运行在不同线程中的相关任务视为单个工作单元来管理,简化错误处理和取消操作。

[#](#新版写法-5) 新版写法​

try (var scope = StructuredTaskScope.<String>open()) {
    Subtask<String> userTask = scope.fork(() -> fetchUser());
    Subtask<String> orderTask = scope.fork(() -> fetchOrder());
    scope.join(); // 等待所有子任务完成或任一失败
    if (userTask.state() == Subtask.State.SUCCESS) {
        return new Response(userTask.get(), orderTask.get());
    } else {
        throw new RuntimeException("Subtask failed", userTask.exception());
    }
}

结构化并发就是来解决并发编程中 线程泄露和资源管理 问题的

  • 自动清理:任一任务失败,其他任务自动取消

  • 异常传播:主线程被中断,子任务也会取消

  • 资源管理:可以配合 try-with-resources 保证资源释放

[#](#新版优点-5) 新版优点​

提高并发代码的可靠性和可观察性,尤其利于错误传播和任务取消。

[#](#_3-性能优化) 3.性能优化

[#](#_3-1-紧凑对象头) 3.1 紧凑对象头​

  • 说明:将对象头从 128 位压缩至 64 位,减少小对象的内存占用。

  • 启用:添加 JVM 参数 -XX:+UseCompactObjectHeaders。

[#](#新版优点-6) 新版优点​

显著减少内存占用(小型对象最多可节省 33%),提升执行效率(CPU 时间减少,GC 频率降低)。测试显示堆占用减少 22%,CPU 时间减少 8%,GC 次数减少 15%。无需修改代码即可受益,对微服务、云环境等内存受限场景尤其有利。

[#](#_3-2-shenandoah-分代垃圾回收器) 3.2 Shenandoah 分代垃圾回收器​

  • 说明:Shenandoah GC 的分代模式正式成为生产就绪特性。

  • 启用:-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational。

[#](#新版优点-7) 新版优点​

针对新生代和老年代采用差异化回收策略,停顿时间降低高达 40%,适合高吞吐应用。

[#](#_4-安全增强) 4.安全增强​

引入一些列加密工具类,实现信息加密,例如引入基于晶格密码的 ML-KEM(密钥封装)和 ML-DSA(数字签名)算法,实现代码如下:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA");
KeyPair kp = kpg.generateKeyPair();
Signature sig = Signature.getInstance("ML-DSA");
sig.initSign(kp.getPrivate());
sig.update(message);
byte[] signature = sig.sign();
// 验证签名
sig.initVerify(kp.getPublic());
sig.update(message);
boolean verified = sig.verify(signature);

font style="color:rgb(44, 62, 80);"</font>

其他特性

【了解】移除 32 位 x86 支持​

Java 25 正式移除了对 32 位 x86 架构的支持。

简单来说就是:32 位系统现在用不了 Java 25 了。

【了解】JFR 性能分析增强​

JFR(Java Flight Recorder)飞行记录器是 JDK 内置的低开销性能监控工具,可以记录程序运行时的详细数据。

它在这个版本获得了几个重要增强,包括更精确地测量 CPU 使用情况、通过协作式采样保证了 JVM 安全性、可以更安全地在生产环境开启分析等。

【了解】Vector API(第 10 次孵化)​

Vector API 继续孵化,主要改进:

  1. 更好的数学函数支持:现在通过 FFM API 调用本地数学库,提高可维护性

  2. Float16 支持增强:在支持的 CPU 上可以自动向量化 16 位浮点运算

  3. VectorShuffle 增强:支持与 MemorySegment 交互

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐