迁移到 Java 25 的原因

Java 25 是一个长期支持(LTS)版本,这使得它成为目前在 Java 8、11、17 或 21 上运行的团队的自然目标。 每个 LTS 版本都接收多年的更新和安全修补程序,因此迁移到 Java 25 使应用程序受支持、安全且能够使用最新的性能和语言改进。

问题不是 应该 迁移到较新的 LTS 版本,而是 何时迁移。 等待时间越长,当前版本与下一个受支持版本之间积累的变更就越多。 迁移到 Java 25 好处明显,尽早而非拖后规划迁移可降低风险。

自 Java 8 以来,每个版本都添加了功能和增强功能。 API 有明显的添加和修改,以及对启动时间、吞吐量、内存使用情况、可伸缩性和开发人员工作效率的改进。 本文重点介绍最具影响力的变化,重点关注自 Java 11 LTS 发布以来推出的 Java 版本:Java 17、Java 21 和 Java 25。

迁移到 Java 25

可以分步转换为 Java 25。 使用较旧的 JDK 开发和构建的代码通常可以在 Java 25 上运行,而无需重新编译。 与任何主要升级一样,请监视已删除的 API、弃用的包、使用内部 API 以及对默认行为的更改,尤其是在垃圾回收方面。

如果您目前使用的是 Java 8 或 11,请先阅读《从 Java 8 迁移到 Java 11》指南,以处理数量最多的一组重大不兼容变更,然后再继续迁移到 Java 17、21 和 25。 如果你已经使用 Java 17 或 21,那么迁移到 Java 25 的工作量通常会小一些,因为模块系统和大多数平台变更带来的调整你基本都已经经历过了。

Tip

GitHub Copilot 应用现代化可帮助评估应用程序、计划升级并自动应用代码更改。 它支持在 Java 8、11、17、21 和 25 各版本之间升级,并在每次更改后构建和测试你的项目,还可帮助处理本文后文描述的行为变化。

Tip

针对旧版 JDK 调优过的 JVM 标志在 Java 25 中可能已被弃用、移除,或不再是最优选择。 可以让 Java Azurejaz命令启动器自动应用针对 JDK 版本和容器或虚拟机资源定制的 JVM 标志,而不是传递过时的设置。 将启动脚本中的 java 命令替换为 jaz,或使用 Dockerfile,即可从中受益。

自 Java 11 以来的高级更改

本部分不枚举自 Java 8 以来所做的每一次更改。 它突出显示了对性能、可伸缩性、诊断、生产力和安全性影响最大的更改。 其中大多数功能已在 Java 17、21 和 25 版本中推出,现已成为 Java 25 所提供的 LTS 基线的一部分。 每个功能都注明了它被集成到哪个 Java 版本中。

使用虚拟线程实现可伸缩性

虚拟线程 [1] 是由 JVM 而不是操作系统管理的轻型线程,可大幅降低写入和运行高吞吐量并发应用程序的成本。 使用虚拟线程,可以采用简单的每请求线程样式编写代码,并且仍可扩展到大量并发操作,这对于 I/O 绑定微服务和请求响应工作负荷来说是理想的。

虚拟线程已在 Java 21 中完成。 Java 24 通过允许虚拟线程同步而不固定其运营商线程 [2],从而消除了关键限制,这提高了使用synchronized块的代码的可伸缩性。

结构化并发和作用域值

作用域值 [3] 提供了一种安全、高效的方法来在线程内和跨线程(包括虚拟线程)共享不可变数据。 它们是线程本地变量的现代化替代方案,能与每任务一线程模型良好配合。

结构化并发 [4] 将相关并发任务的组视为单个工作单元,从而简化了错误处理和取消。 该特性在 Java 21 中首次作为预览功能推出,并且仍在持续演进,与虚拟线程也天然契合。

语言生产力

通过 Java 14 到 Java 25 提供的一系列语言增强功能使代码更加简洁、更安全且更易于阅读:

  • 切换表达式 [5] (Java 14) 允许switch返回值并使用更清晰的箭头语法。
  • 针对 instanceof [6] (Java 16) 的模式匹配消除了类型检查后进行显式强制转换的需求。
  • 记录 [7](Java 16)将不可变数据建模为固定值集合的透明载体,从而减少样板代码。
  • 密封类 [8] (Java 17) 允许你控制哪些类可以扩展或实现类型。
  • 文本块 [9] (Java 15) 简化了多行字符串文本。
  • 用于 switch 的模式匹配[10](Java 21)和 记录模式[11](Java 21)让你能够以清晰且安全的方式表达复杂的条件逻辑并进行数据解构。
  • 排序集合 [12] (Java 21) 为具有定义的遇到顺序的集合添加统一 API,包括访问第一个元素和最后一个元素。
  • 未命名的变量和模式 [13] (Java 22) 允许显式标记未使用的变量和模式组件。
  • 模块导入声明 [14] (Java 25) 允许使用单个声明导入整个模块的导出包。
  • 压缩源文件和实例主方法 [15] (Java 25) 减少了小型程序所需的仪式,这使得Java更容易学习,更快地制作原型。
  • 灵活的构造函数体 [16] (Java 25) 允许在调用 super(...)this(...) 之前先执行语句,从而改进验证和初始化。

性能和启动

多个运行时更改可提高吞吐量、内存占用量和启动时间:

  • 压缩对象标头 [17] (Java 25) 可减小 64 位平台上的对象标头的大小。 这种减少降低了堆使用率,并能改善分配密集型工作负荷的性能。
  • 类数据共享(CDS) 通过运行时的内存映射存档类来降低启动时间。 默认 CDS 存档 [18] (Java 12) 和动态 CDS 存档 [19] (Java 13) 使此功能更易于采用,而无需手动训练运行。
  • 预先类加载和链接 [20](Java 24),以及预先命令行易用性 [21](Java 25)和预先方法分析 [22](Java 25),通过重用应用程序归档文件中记录的成果来缩短启动和预热时间。 这些功能是 Project Leyden 为了让 Java 启动更快所做努力的一部分。

这些改进对于云原生工作负载和无服务器工作负载尤其有用,快速启动和占用空间较小直接转化为更好的缩放和更低的成本。

垃圾回收

Java 25 提供了适用于广泛工作负载的成熟低停顿垃圾收集器:

  • ZGC [23] (Java 15) 和 Shenandoah [24] (Java 15) 是可用于生产的收集器,专为在大堆上实现低暂停时间而设计。
  • G1GC 仍然是默认收集器,并持续得到改进,包括区域固定机制 [25](Java 22),从而更顺畅地与原生代码交互。
  • 代系 ZGC [26] (Java 21) 通过保持单独的代系来提高效率。 从 Java 23 起,ZGC 默认在代系模式下运行 [27],非代系模式在 Java 24 中删除。
  • 分代 Shenandoah [28](Java 25)为 Shenandoah 收集器增加了分代模式,以便在内存压力下提高吞吐量和弹性。

JVM 为平均用例设置 GC 默认值。 根据应用程序的要求优化这些默认值和其他 GC 设置以优化吞吐量或延迟。

Tip

默认的垃圾回收器以及许多 JVM 默认设置在不同 Java 版本之间有所不同,因此,针对 Java 8 或 11 调优的设置在 Java 25 上可能已不再是最优选择。 用于 Java () 的 jaz读取容器的 cgroup 内存和 CPU 限制,并自动应用针对 JDK 版本和环境定制的 JVM 标志。

诊断和可观测性

诊断功能在各个版本中均有所改进,无论是在语言本身还是在 Java 飞行记录器(JFR)方面:

  • 有用的 NullPointerExceptions [29] (Java 14) 能精确描述哪个变量为 null,从而加快调试速度。
  • JFR 事件流 [30](Java 14)使工具能够持续接收分析和诊断数据,而不是从转储文件中获取这些数据。
  • JFR CPU 时间性能分析 [31](Java 25)在 Linux 上新增了实验性的基于 CPU 时间的方法性能分析。
  • JFR 合作采样 [32] (Java 25) 提高了堆栈采样的稳定性。
  • JFR 方法计时和跟踪 [33] (Java 25)允许你无需修改应用程序代码即可时间和跟踪特定方法。

安全性和加密

Java 25 增强了平台的安全态势,包括准备量子后世界:

  • Edwards-Curve 数字签名算法 (EdDSA) [34] (Java 15) 添加了现代高性能签名方案。
  • 密钥封装机制 API [35] (Java 21) 为 KEM 算法提供标准 API。
  • 量子抗量子加密增加了基于模块的键封装机制(ML-KEM) [36] (Java 24) 和数字签名算法 (ML-DSA) [37] (Java 24) 的标准实现。
  • 密钥派生函数 API [38] (Java 25) 为密钥派生函数提供标准 API。

本地互操作性

Foreign Function and Memory API [39] (Java 22) 提供了一种安全、高效和纯Java方法来调用本机库和访问本机内存。 这是Java本机接口(JNI)的新式替代品,可减少样板并提高安全性。

工具和库

多项新增功能可改进日常开发,减少对第三方工具的需求:

  • 打包工具 (jpackage [40] (Java 16) 为 Java 应用程序创建本机安装程序和包。
  • 简单 Web 服务器 [41] (Java 18) 提供用于原型制作和测试的最小静态文件 HTTP 服务器。
  • 增强的伪随机数生成器 [42] (Java 17) 为随机数生成添加新接口和实现。

需要规划应对的行为变化

由于Java 11 更改了默认行为,因此请在升级之前查看这些更改:

  • 强封装 JDK 内部 [43] (Java 17) 默认阻止了对大多数内部 API 的反射访问。 接触 sun.* 或其他内部包的代码或库可能需要更新。
  • 默认情况下,UTF-8 [44] (Java 18) 使 UTF-8 成为标准Java API 的默认字符集。 依赖于特定于平台的默认字符集的应用程序的行为可能有所不同。
  • 弃用终结方法以进行移除 [45] (Java 18) 表明 finalize() 终将被移除。 迁移到 try-with-resources 或 java.lang.ref.Cleaner
  • 准备禁止动态加载代理 [46](Java 21)会在将代理加载到正在运行的 JVM 中时发出警告。 某些监视和检测工具可能需要配置更改。

Tip

GitHub Copilot 应用现代化可以帮助你在升级时自动评估并修复这些行为变更。

容器和云

针对 Docker 和其他容器运行时引入的 JVM 容器感知继续改进。 JVM 读取由容器控制组(cgroups)设置的 CPU 和内存约束,并相应地调整堆和其他资源的大小。 结合更快的启动、更小的占用空间和虚拟线程,Java 25 非常适合Azure上的容器化和无服务器部署。

如果您在 Azure 容器或虚拟机上运行 Java 工作负载,Azure Command Launcher for Javajaz)可以为您应用针对云优化且适合相应版本的 JVM 默认设置。

后续步骤

References

[1] Oracle Corporation,“JEP 444:虚拟线程”。(在线)。 可用: https://openjdk.org/jeps/444.

[2] Oracle Corporation,“JEP 491:同步虚拟线程而无固定。”(在线)。 可用: https://openjdk.org/jeps/491.

[3] Oracle Corporation,“JEP 506:作用域值”。(在线)。 可用: https://openjdk.org/jeps/506.

[4] Oracle Corporation,“JEP 453:结构化并发(预览版)。(在线)。 可用: https://openjdk.org/jeps/453.

[5] Oracle Corporation,“JEP 361:切换表达式”。(在线)。 可用: https://openjdk.org/jeps/361.

[6] Oracle Corporation, “JEP 394: instanceof 的模式匹配”。(在线)。 可用: https://openjdk.org/jeps/394.

[7] Oracle Corporation,“JEP 395:记录”。(在线)。 可用: https://openjdk.org/jeps/395.

[8] Oracle Corporation,“JEP 409:密封类”。(在线)。 可用: https://openjdk.org/jeps/409.

[9] Oracle Corporation,“JEP 378:文本块”。(在线)。 可用: https://openjdk.org/jeps/378.

[10] Oracle Corporation,“JEP 441:switch 的模式匹配。”(在线)。 可用: https://openjdk.org/jeps/441.

[11] Oracle Corporation,“JEP 440:记录模式”。(在线)。 可用: https://openjdk.org/jeps/440.

[12] Oracle Corporation,“JEP 431:有序集合。”(在线)。 可用: https://openjdk.org/jeps/431.

[13] Oracle Corporation,“JEP 456:未命名的变量和模式”。(在线)。 可用: https://openjdk.org/jeps/456.

[14] Oracle Corporation,“JEP 511:模块导入声明”。(在线)。 可用: https://openjdk.org/jeps/511.

[15] Oracle Corporation,“JEP 512:压缩源文件和实例主方法”。(在线)。 可用: https://openjdk.org/jeps/512.

[16] 甲骨文公司,“JEP 513:灵活的构造函数体”。(在线)。 可用: https://openjdk.org/jeps/513.

[17] Oracle Corporation, “JEP 519: Compact Object Headers.(在线)。 可用: https://openjdk.org/jeps/519.

[18] Oracle Corporation,“JEP 341:默认 CDS 存档”。(在线)。 可用: https://openjdk.org/jeps/341.

[19] Oracle Corporation,“JEP 350:动态 CDS 归档”。(在线)。 可用: https://openjdk.org/jeps/350.

[20] Oracle Corporation,“JEP 483:提前类加载与链接。”(在线)。 可用: https://openjdk.org/jeps/483.

[21] Oracle Corporation,“JEP 514:提前命令行人机工程学。”(在线)。 可用: https://openjdk.org/jeps/514.

[22] Oracle Corporation,“JEP 515:提前方法分析”。(在线)。 可用: https://openjdk.org/jeps/515.

[23] Oracle Corporation,“JEP 377:ZGC:一种可扩展的低延迟垃圾回收器”。(在线)。 可用: https://openjdk.org/jeps/377.

[24] 甲骨文公司,“JEP 379:Shenandoah:低暂停时间垃圾回收器”。(在线)。 可用: https://openjdk.org/jeps/379.

[25] Oracle Corporation,“JEP 423:G1 的区域固定。”(在线)。 可用: https://openjdk.org/jeps/423.

[26] Oracle Corporation,“JEP 439:Generational ZGC。”(在线)。 可用: https://openjdk.org/jeps/439.

[27] Oracle Corporation, “JEP 474: ZGC: 代系模式默认”。(在线)。 可用: https://openjdk.org/jeps/474.

[28] Oracle Corporation, “JEP 521: Generational Shenandoah.(在线)。 可用: https://openjdk.org/jeps/521.

[29] Oracle Corporation,“JEP 358:有帮助的空指针异常”。(在线)。 可用: https://openjdk.org/jeps/358.

[30] Oracle Corporation, “JEP 349: JFR 事件流式处理”。(在线)。 可用: https://openjdk.org/jeps/349.

[31] Oracle Corporation,“JEP 509:JFR CPU 时间分析(实验性)。”(在线)。 可用: https://openjdk.org/jeps/509.

[32] Oracle Corporation, “JEP 518: JFR 合作采样”。(在线)。 可用: https://openjdk.org/jeps/518.

[33] Oracle Corporation,“JEP 520:JFR 方法计时与跟踪。”(在线)。 可用: https://openjdk.org/jeps/520.

[34] Oracle Corporation,“JEP 339:Edwards-Curve 数字签名算法(EdDSA)。(在线)。 可用: https://openjdk.org/jeps/339.

[35] Oracle Corporation,“JEP 452:密钥封装机制 API”。(在线)。 可用: https://openjdk.org/jeps/452.

[36] Oracle Corporation,“JEP 496:基于模格的抗量子密钥封装机制”。(在线)。 可用: https://openjdk.org/jeps/496.

[37] Oracle Corporation,“JEP 497:抗 Quantum 模块格基数字签名算法。”(在线)。 可用: https://openjdk.org/jeps/497.

[38] Oracle Corporation,“JEP 510:密钥派生函数 API”。(在线)。 可用: https://openjdk.org/jeps/510.

[39] Oracle Corporation, “JEP 454:外部函数和内存 API。”(在线)。 可用: https://openjdk.org/jeps/454.

[40] Oracle Corporation,“JEP 392:打包工具”。(在线)。 可用: https://openjdk.org/jeps/392.

[41] Oracle Corporation,“JEP 408:简单 Web 服务器”。(在线)。 可用: https://openjdk.org/jeps/408.

[42] Oracle Corporation,“JEP 356:增强的伪随机数生成器”。(在线)。 可用: https://openjdk.org/jeps/356.

[43] Oracle Corporation,《JEP 403:JDK 内部的强封装》。(在线)。 可用: https://openjdk.org/jeps/403.

[44] Oracle Corporation, “JEP 400: UTF-8 默认。(在线)。 可用: https://openjdk.org/jeps/400.

[45] Oracle Corporation,“JEP 421:弃用终结方法以进行移除。”(在线)。 可用: https://openjdk.org/jeps/421.

[46] Oracle Corporation,“JEP 451:准备禁止动态加载代理”。(在线)。 可用: https://openjdk.org/jeps/451.