Java 25 是继 Java 21 之后的又一个长期支持(LTS)版本,于 2025 年 9 月 16 日发布,包含 18 个 JEP。Java 21 引入的虚拟线程、记录模式等在 25 中继续打磨成熟,同时 25 带来了模块导入、紧凑源文件、作用域值正式化等一批新特性,并在 AOT 提前编译、对象头压缩、JFR 可观测性等方面有显著提升。以下是对 Java 25 相比 Java 21 的主要新特性的详细总结,重点突出其提升,并尽量简洁:

语言特性改进

  • 紧凑源文件与实例 main 方法(Compact Source Files and Instance Main Methods,JEP 512,Java 25 正式化)
    • 允许省略类声明、String[] args 参数和 public static 修饰符,直接写一个 main 方法即可运行,新手和脚本场景更友好;同时默认隐式导入 java.io.IO,可直接用 printlnreadln 等方法。

    • 示例:

      // 整个文件就这一段,无需 class 包装
      void main() {
          String name = readln("你的名字?");
          println("你好," + name);
      }
    • Java 21 必须显式声明 public static void main(String[] args) 和类结构。

  • 模块导入声明(Module Import Declarations,JEP 511,Java 25 正式化)
    • 支持用 import module 一次性导入整个模块的导出包,免去逐个 import,尤其在大量使用 java.base 时非常省事。

    • 示例:

      import module java.base;
      // List、Map、Stream、Path、Collection 等可直接使用,无需逐条 import
    • Java 21 只能逐个类/包导入,缺乏这种聚合导入能力。

  • 灵活的构造器体(Flexible Constructor Bodies,JEP 513,Java 25 正式化)
    • 允许在调用 super(...) 之前执行语句(如参数校验、字段初始化),且显式构造器中可不写 super(),构造器逻辑更自由。

    • 示例:

      public class PositiveBigInteger extends BigInteger {
          public PositiveBigInteger(long value) {
              if (value <= 0) throw new IllegalArgumentException();
              super(value); // 语句可在 super 调用之前执行
          }
      }
    • Java 21 要求 super() 必须是构造器首条语句,校验逻辑往往要拆到静态工厂方法中。

  • 基本类型模式匹配(Primitive Types in Patterns, instanceof, and switch,JEP 507,Java 25 第三次预览)
    • 将模式匹配扩展到基本类型,可在 instanceofswitch 中直接匹配 intlongdouble 等,并在不同数值类型间安全转换。

    • 示例:

      String result = switch (x) {
          case int i when i > 0 -> "正整数: " + i;
          case long l           -> "long: " + l;
          case double d         -> "double: " + d;
          default               -> "其他";
      };
    • Java 21 的模式匹配仅支持引用类型,基本类型需手动拆箱/类型判断。

API 和标准库增强

  • 作用域值(Scoped Values,JEP 506,Java 25 正式化)
    • 项目 Loom 的另一成果,提供比 ThreadLocal 更安全、更轻量、不可变的值传递方式,特别适合虚拟线程场景下的上下文传播,生命周期随作用域自动结束。

    • 示例:

      static final ScopedValue<String> USER = ScopedValue.newInstance();
      ScopedValue.where(USER, "alice").run(() -> {
          System.out.println("当前用户: " + USER.get());
      });
    • Java 21 中作用域值为预览特性;ThreadLocal 在百万级虚拟线程下内存占用高、易泄漏。

  • 密钥派生函数 API(Key Derivation Function API,JEP 510,Java 25 正式化)
    • 标准化 KDF(如 HKDF)的 API,便于从主密钥派生子密钥,告别依赖各厂商私有实现。

    • 示例:

      KDF kdf = KDF.getInstance("HKDF-SHA256");
      SecretKey key = kdf.deriveKey(
          "HKDF-Expand".toCharArray(),
          new HKDFParameterSpec.Expand(masterKey, null, 32));
    • Java 21 无统一 KDF API,需借助第三方库或手写实现。

  • 稳定值(Stable Values,JEP 502,Java 25 预览)
    • 引入延迟初始化、不可变、可被 AOT 预计算的值,兼顾 final 字段的不可变性与延迟初始化的灵活性,配合提前编译进一步提升启动性能。

    • 示例:

      static final StableValue<Config> CONFIG = StableValue.of();
      Config get() {
          return CONFIG.orElseSet(() -> loadConfig());
      }
    • Java 21 无此机制,延迟初始化通常用 volatile 字段 + 双重检查锁实现,较为繁琐且无法被 AOT 优化。

  • 加密对象 PEM 编码(PEM Encodings of Cryptographic Objects,JEP 470,Java 25 预览)
    • 为密钥、证书等 JCA 对象增加标准 PEM 文本格式编解码支持,与 OpenSSL 等生态互通更顺畅。

    • 示例:

      // 生成密钥并以 PEM 文本形式输出 / 从 PEM 文本读回
      String pem = Encoders.PEM.encode(publicKey);
    • Java 21 需借助 Base64.getMimeEncoder() 自行拼装 -----BEGIN ...-----,缺乏官方 API。

  • 向量 API(Vector API,JEP 508,Java 25 第十次孵化)
    • 继续孵化,表达可寄存器化的向量计算以榨取 CPU SIMD 能力,仍为孵化模块。
    • Java 21 为第八次孵化,25 进一步对齐新硬件指令。

并发模型

  • 结构化并发(Structured Concurrency,JEP 505,Java 25 第五次预览)
    • 将多个并发任务视为一个工作单元,任一失败即取消其余,简化错误处理与资源管理;与作用域值、虚拟线程协同。

    • 示例:

      try (var scope = StructuredTaskScope.open()) {
          Subtask<String> t1 = scope.fork(() -> fetch("a"));
          Subtask<String> t2 = scope.fork(() -> fetch("b"));
          scope.join(); // 等待全部完成
          System.out.println(t1.get() + ", " + t2.get());
      }
    • Java 21 为首次预览(ShutdownOnFailure 等旧 API),25 调整为更简洁的 open()/Subtask API,但仍是预览态。

性能和 JVM 优化

  • 紧凑对象头(Compact Object Headers,JEP 519,Java 25 正式化)
    • 将普通对象头从约 96-128 位压缩到 64 位(合并标记字与类指针),显著降低堆内存占用,对大量小对象的应用(尤其虚拟线程)收益明显。
    • Java 21 对象头为传统双字(含类指针与标记字),小对象内存开销较大。
  • 分代 Shenandoah(Generational Shenandoah,JEP 521,Java 25 正式化)
    • Shenandoah GC 升级为分代,按年轻代/老年代分别回收,降低扫描与暂停开销。
    • Java 21 的 Shenandoah 为非分代,低延迟有余但吞吐效率不如分代版本。
  • 提前编译(AOT)方法剖析与命令行人体工程学(JEP 515、JEP 514,Java 25 正式化)
    • 项目 Leyden 首批落地成果:可在构建期进行方法级剖析并生成 AOT 缓存,启动时直接复用,配合更顺手的 java -AOT 命令行,大幅缩短冷启动时间。
    • Java 21 无 AOT 缓存能力,启动期需重复进行热点剖析,冷启动较慢。
  • JFR 可观测性增强(JEP 509、518、520,Java 25 实验/正式化)
    • 新增 JFR CPU 时间剖析(509,实验性)、协作式采样(518)、方法计时与追踪(520),降低采样偏差与观测开销。
    • Java 21 的 JFR 缺少 CPU 时间级剖析,采样偏差较大。

弃用和移除

  • 移除 32 位 x86 移植(JEP 503,Java 25)
    • 移除 windows-x86linux-x86 等 32 位 x86 构建,集中资源到 64 位与 ARM/RISC-V 等主流平台。
    • Java 21 仍提供 32 位 x86 移植(已弱化)。
  • sun.misc.Unsafe 内存访问方法进一步弃用
    • 继续推进移除 Unsafe 的内存操作方法,推动迁移至外部函数与内存 API(FFM API)。
    • Java 21 中这些方法仍可用(FFM API 刚正式化)。

迁移和兼容性

  • 向后兼容性
    • Java 25 保持了较高的向后兼容性,从 Java 21 迁移通常较平滑,但需注意 32 位 x86 不再提供、Unsafe 内存方法持续弃用等。
  • 挑战
    • 仍在预览的特性(结构化并发、基本类型模式、稳定值)在生产使用需加 --enable-preview,API 可能再变。
    • 若依赖 32 位 x86 原生库,需迁移到 64 位。

其他改进

  • JDK 25 作为 LTS
    • 自 25 起,Oracle 将 LTS 间距从 3 年缩短为 2 年;Java 25 获得 Oracle 至少 8 年 premier 支持(至 2033 年)。
  • 工具链与开发者体验
    • 紧凑源文件 + 模块导入显著降低入门门槛,jshell 与单文件脚本更顺手;AOT 缓存让微服务、CLI 工具冷启动更快。

总结

Java 25 相较 Java 21 的最大亮点是 作用域值正式化结构化并发持续演进,让虚拟线程时代的并发上下文与任务编排更安全简洁;模块导入紧凑源文件/实例 main 大幅提升代码简洁度与新手体验;灵活构造器体基本类型模式匹配 补齐了语言层面的最后几块短板;KDF APIPEM 编码 增强了加密生态。性能方面,紧凑对象头分代 ShenandoahAOT 提前编译 让 Java 在内存占用、低延迟和冷启动上更进一步;JFR 可观测性增强 让性能分析更精准。作为新的 LTS 版本(支持至 2033 年),Java 25 是 Java 21 的理想升级目标,尤其适合追求现代化语言特性、更优启动性能与长期支持的项目。