Java 25 的新特性

1、概览

Java 25 即将发布!这个新的短期版本计划于 2025 年 9 月推出,全面增强了 Java 语言、标准库、API 和运行时环境。

本文将带你了解截至 2025 年 6 月 Java 25 引入的所有新特性和变化。通过简单代码示例和详细解析,带你全面了解这些更新。

2、Java 25 新特性详解

Java 25 引入了一系列语言和编译器增强功能,旨在使语言表达更丰富、代码更简洁。这些特性既优化了日常开发体验,也提升了高级模块化场景下的编程效率。

2.1、原始类型模式匹配(JEP 507 - 第三预览版)

现在,模式匹配可支持 switchinstanceof 语句中的原始类型。例如:

static void test(Object obj) {
    if (obj instanceof int i) {
        System.out.println("It's an int: " + i);
    }
}

JEP 507 将原始类型纳入 Java 模式匹配框架,使这类表达式更直观并减少样板代码。该提案是语言层面统一类型模式匹配整体规划的重要组成部分。

2.2、模块化导入声明(JEP 511 - 预览版)

JEP 511 引入了模块导入声明功能,允许通过 import 语句声明模块依赖关系,从而提升模块化代码的可读性。传统模块依赖仅能在 module-info.java 中使用 requires 指令声明,而该提案支持在 Java 文件顶部通过 import module 语句声明模块依赖(类似传统导包语法),这一改进既增强了代码清晰度,也使开发工具能更精准推断依赖关系。例如:

import module java.base; 
//...

public class Main {
    public static void main(String[] args) {
        Date d = new Date();
        System.out.println("Resolved Date: " + d);
    }
}

但需注意避免引用歧义。以下示例代码演示具体用法:

import module java.base;      // 导出包含 java.util.Date 的 java.util 模块
import module java.sql;       // 导出包含 java.sql.Date 的 java.sql 模块

public class Main {
    public static void main(String[] args) {
        Date d = Date.valueOf("2025-06-15");
        System.out.println("Resolved Date: " + d);
    }
}

编译该类时将出现以下提示信息:

error: reference to Date is ambiguous
         Date d = Date.valueOf("2025-06-15");
         ^
   both class java.sql.Date in java.sql and class java.util.Date in java.util match
   error: reference to Date is ambiguous

此时解决方案是显式导入需要使用的具体类:

import module java.base;
import module java.sql;

import java.sql.Date;

public class Main {
    public static void main(String[] args) {
        Date d = Date.valueOf("2025-06-15");
        System.out.println("Resolved Date: " + d);
    }
}

该变更还支持从星号导入切换为模块级导入:

// 这些导入语句可合并为:
import javax.xml.*; 
import javax.xml.parsers.*; 
import javax.xml.stream.*;

可简化为:

import module java.xml;

尽管不建议滥用星号导入和模块导入,但该特性确实使导入和依赖定义更加简洁精炼。

2.3、紧凑源文件(JEP 512)与实例 main 方法

Java 现已支持顶层实例 main 方法和无 class 紧凑文件。这意味着以下声明现在有效:

void main() {
    System.out.println("Hello from Java 25!");
}

JEP 512 基于 Java 21 引入的简化启动器机制,允许开发者无需类声明即可编写快速脚本或演示程序。这些紧凑源文件特别适合教学、脚本编写和快速原型开发,既降低了新手的入门门槛,也缩短了学习曲线。

2.4、灵活构造函数体(JEP 513 - 最终版)

灵活构造函数体(JEP 513)允许多个构造函数委托至公共初始化体,实现方式如下:

class Person {
    final int age;

    Person(int age) {
        this.age = age;
    }
}

class Employee extends Person {
    final String name;

    Employee(String name, int age) {
        if (age < 18 || age > 67)
            throw new IllegalArgumentException("Age must be between 18 and 67");
        super(age); // Java 25 中 super() 不再必须作为构造函数的第一条语句
        this.name = name;
    }

    public static void main(String[] args) {
        var emp = new Employee("Alice", 35);
        System.out.println("Person age set: " + emp.age);
    }
}

在 JEP 513 之前,Java 构造函数必须将 super(...)this(...) 作为第一条语句,这常导致校验逻辑或初始化代码重复,或被迫提取到静态辅助方法中。JEP 513 允许在构造函数调用前执行代码,使参数校验和共享初始化逻辑能集中处理,既提升了代码可读性和快速失败能力,又保证了对象完整性,同时不违反 Java 的构造规则。

3、API 增强

Java 25 除持续推进处于预览/最终/早期阶段的新 API 外,还对现有 API 进行了多项改进。

3.1、作用域值(JEP 506 - 最终版)

JEP 506 提供了轻量级、不可变且线程安全的 ThreadLocal 替代方案,专为与虚拟线程协同工作而设计:

import java.lang.ScopedValue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ScopedUserExample {
    static final ScopedValue<String> USER = ScopedValue.newInstance();

    public static void main(String[] args) {
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            executor.submit(() -> ScopedValue.where(USER, "Alice").run(() -> {
                System.out.println("Thread: " + Thread.currentThread());
                System.out.println("User: " + USER.get());
            }));

            executor.submit(() -> ScopedValue.where(USER, "Bob").run(() -> {
                System.out.println("Thread: " + Thread.currentThread());
                System.out.println("User: " + USER.get());
            }));

            // 添加延迟确保输出在 main 退出前显示
            Thread.sleep(200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

作用域值(Scoped Values)通过安全、高性能且不可变的方式在调用链间传递上下文,尤其适合虚拟线程和结构化并发场景。相比 ThreadLocal,它避免了内存泄漏和同步开销,提供了更高效的替代方案。

注:使用作用域值与虚拟线程时,访问作用域值的逻辑必须封装在 ScopedValue.where(...).run(...) 作用域内。仅将任务提交至 executor 作用域并不足够,任务本身必须在作用域(Scope)内创建才能保留绑定值。

3.2、结构化并发(JEP 505 - 第五预览版)

JEP 505 通过将相关线程视为具有明确生命周期的单一工作单元来简化并发编程。第五预览版改用 StructuredTaskScope.open() 静态工厂方法替代构造函数和独立策略方法,使自定义合并与错误处理行为的定义更一致灵活。以下是新语法示例:

import java.util.concurrent.StructuredTaskScope;

public class StructuredExample {
    static String fetchUser() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return "Alice";
    }

    static String fetchOrder() {
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return "Order#42";
    }

    public static void main(String[] args) throws Exception {
        try (var scope = StructuredTaskScope.<String>open()) {
            var userTask = scope.fork(() -> fetchUser());
            var orderTask = scope.fork(() -> fetchOrder());

            scope.join();

            System.out.println(userTask.get() + " - " + orderTask.get());
        }
    }
}

结构化并发帮助管理逻辑关联的多个并发任务,确保子线程作为整体完成或取消,从而提升多线程应用的可靠性和可读性。

3.3、StableValue API(JEP 502 - 预览版)

稳定值(Stable Value)API(JEP 502)将 Optional 式语义扩展至上下文稳定的不可变值:

import java.lang.StableValue;

public class StableExample {
    public static void main(String[] args) {
        // 创建未设置的 StableValue
        var greeting = StableValue.<String>of();

        String message = greeting.orElseSet(() -> "Hello from StableValue!");
        System.out.println(message);
    }
}

稳定值提供了一套 API,用于跨线程或计算过程安全共享不可变的上下文稳定值。该特性适用于缓存、惰性求值或稳定作用域内的一致性读取等场景,并能与结构化并发良好集成。

3.4、PEM 编码(JEP 470 - 预览版)

JEP 470 通过标准 API 新增了对 PEM 格式加密密钥及证书的读写支持,简化后的操作如下:

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class PEMExample {
    public static void main(String[] args) {
      String pem = """
        -----BEGIN PUBLIC KEY-----
        MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgjDohS0RHP395oJxciVaeks9N
        KNY5m9V1IkBBwYsMGyxskrW5sapgi9qlGSYOma9kkko1xlBs17qG8TTg38faxgGJ
        sLT2BAmdVFwuWdRtzq6ONn2YPHYj5s5pqx6vU5baz58/STQXNIhn21QoPjXgQCnj
        Pp0OxnacWeRSnAIOmQIDAQAB
        -----END PUBLIC KEY-----
        """;

        try {
            String base64 = pem.replaceAll("-----.*-----", "").replaceAll("\\s", "");
            byte[] keyBytes = Base64.getDecoder().decode(base64);

            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory factory = KeyFactory.getInstance("RSA");
            PublicKey key = factory.generatePublic(spec);

            System.out.println("Loaded key: " + key.getAlgorithm());
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }
}

现在可直接通过 Java Security API 处理 PEM 编码对象(如 X.509 证书和 RSA 密钥),无需第三方库或手动转换。该特性增强了与基于 OpenSSL 系统的互操作性,并简化了安全通信流程。

3.5、向量 API(JEP 508 - 第十孵化器版)

JEP 508 提供的 API 能将向量计算可靠地编译为最优化的向量硬件指令:

import jdk.incubator.vector.*;

public class VectorExample {
    public static void main(String[] args) {
        float[] left = {1f, 2f, 3f, 4f};
        float[] right = {5f, 6f, 7f, 8f};

        FloatVector a = FloatVector.fromArray(FloatVector.SPECIES_128, left, 0);
        FloatVector b = FloatVector.fromArray(FloatVector.SPECIES_128, right, 0);
        FloatVector c = a.add(b);

        float[] result = new float[FloatVector.SPECIES_128.length()];
        c.intoArray(result, 0);

        System.out.println("Vector result: " + java.util.Arrays.toString(result));
    }
}

需启用参数:--enable-preview --add-modules jdk.incubator.vector

向量 API 支持在现代 CPU 上高效执行数据并行计算,通过利用 SIMD 指令使 Java 代码达到媲美手工调优原生代码的性能,目前仍处于孵化演进阶段。

3.6、密钥派生函数 API(JEP 510 - 最终版)

Java 25 为基于密码的密钥派生函数(如 PBKDF2scrypt)引入了标准 API:

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class KeyDerivationExample {
    public static void main(String[] args) throws Exception {
        char[] password = "hunter2".toCharArray();
        byte[] salt = "somesalt".getBytes();
        PBEKeySpec spec = new PBEKeySpec(password, salt, 65536, 256);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        SecretKey key = factory.generateSecret(spec);

        System.out.println("Derived key format: " + key.getFormat());
    }
}

JEP 510 标准化了从用户密码派生加密密钥的常用加密原语访问方式,既降低了对第三方库的依赖,又提供了开箱即用的安全实现。

4、其他变更

Java 25 的变更还包括配置移除、基于平台的更新和功能增强。

4.1、移除 32 位 x86 移植版本(JEP 503 - 最终版)

JEP 503 移除了 OpenJDK 对传统 32 位 x86 架构的支持,该提案消除了对逐渐失去相关性的平台的维护成本,而 64 位 x86 和 ARM64 移植版本仍获完整支持。

4.2、JFR CPU 时间分析(JEP 509 - 实验性功能)

JEP 509 为 Java Flight Recorder(JFR)新增基于 CPU 时间的分析支持,该特性可记录并分析特定方法或线程消耗的 CPU 时间,从而提升性能诊断能力(尤其适用于多线程和 I/O 密集型场景)。通过 JDK.CPULoad 及相关 JFR 事件实现自定义记录:

java
  -XX:StartFlightRecording=filename=cpu-time.jfr,duration=10s,settings=profile
  --enable-preview
  MyApp

随后通过 JDK Mission Control 或 VisualVM 分析 CPU time.JFR 文件,即可观测各方法和线程的 CPU 使用情况。

4.3、AOT 编译命令行易用性改进(JEP 514 - 最终版)

AOT 编译命令行易用性改进(JEP 514)通过优化 jaotc 和基于 GraalVM 的 AOT 工具链命令选项提升启动性能,使静态部署和原生镜像场景能更便捷地获得更优的启动速度。

4.4、AOT 方法性能分析(JEP 515 - 最终版)

JEP 515 支持在 AOT 编译期间进行方法级性能分析以优化决策,通过将方法使用频率纳入编译策略提升 AOT 编译 Java 程序的性能,同时帮助 AOT 引擎更智能地制定内联和优化策略。

4.5、JFR 协作式采样(JEP 518 - 实验性功能)

JEP 518 允许应用程序向 Java Flight Recorder 建议安全采样点。协同采样通过将采样与应用程序定义的安全点对齐来降低开销,在最大限度减少对性能敏感代码干扰的同时提高准确性。

4.6、紧凑对象头(JEP 519 - 预览版)

JEP 519 在 64 位架构上减小了对象头大小。该变更通过在对象头中对同步和标识数据采用紧凑布局,从而缩减了 Java 对象的内存占用。这一改进尤其有利于大型堆和微服务环境。

4.7、JFR 方法计时与追踪(JEP 520 - 实验性)

JEP 520 通过详细的逐方法计时和调用追踪信息增强了 JFR 。我们开发者能更精细地查看哪些方法消耗最多时间,从而实现更深入的分析和更好的瓶颈识别。

4.8、分代式 Shenandoah(JEP 521 - 最终版)

JEP 521 为 Shenandoah 垃圾收集器增加了分代支持。分代式 GC 通过将年轻代收集与长期存活对象分开优化,从而提升了吞吐量并改善了暂停时间表现。该特性使 Shenandoah 在效率方面与 G1 和 ZGC 等收集器看齐。

5、开发者须知

如你所见,Java 25 中的许多特性仍处于预览或孵化阶段。要编译和运行使用这些特性的代码,必须启用它们。

  • --enable-preview:所有预览特性必须启用,否则会出现编译错误。
  • --add-modules <name>:孵化模块必须添加,例如我们之前使用的 jdk.incubator.vector
  • --release 25:编译时建议指定,以针对 Java 25 平台。

注意:预览版和孵化器 API 可能在后续版本中变更或移除。我们应避免在生产环境使用这些特性,或持续关注官方 JDK 文档和发行说明以获取错误修复和问题预警。基于此,使用这些特性时需要:

# 编译时需要执行:
javac --enable-preview --release 25 --add-modules jdk.incubator.vector MyClass.java

# 运行时需要执行:
java --enable-preview --add-modules jdk.incubator.vector MyApp

这种方式可以提示 Java 虚拟机 (JVM) 在编译期和运行时允许使用这些特性。

6、总结

Java 25 延续了该平台向现代化和高效能的稳步演进。本次版本完善了多项预览特性,引入了新 API,并从语言语法到运行时诊断及内存管理等各个层面实现了性能提升。

该版本还彰显了 Java 对现代硬件支持的承诺,包括性能剖析和附加特性。虽然 Java 25 是短期支持版本,但其提供的显著优势和新功能仍值得开发者采用并对特性进行反馈,这些反馈将直接影响未来 LTS 版本(如 Java 27)的形态。Java 25 的完整变更清单详见 JDK 发布说明


Ref:https://www.baeldung.com/java-25-features