Java 25 LTS 版本已按计划于2025年9月16日正式发布,该版本提供18项新特性(含6项预览功能),延续了两年发布一次LTS版本的策略。
::: info JEP 470: PEM Encodings of Cryptographic Objects (Preview)
Introduce an API for encoding objects that represent cryptographic keys, certificates, and certificate revocation lists into the widely-used Privacy-Enhanced Mail (PEM) transport format, and for decoding from that format back into objects. This is a preview API.
:::
引入一个 API,用于将表示加密密钥、证书和证书吊销列表的对象编码为广泛使用的隐私增强型邮件 (PEM) 传输格式,并从该格式解码回对象。这是一个预览 API。
::: info JEP 502: Stable Values (Preview)
Introduce an API for stable values, which are objects that hold immutable data. Stable values are treated as constants by the JVM, enabling the same performance optimizations that are enabled by declaring a field final. Compared to final fields, however, stable values offer greater flexibility as to the timing of their initialization. This is a preview API.
:::
为稳定值引入 API,稳定值是保存不可变数据的对象。稳定值被 JVM 视为常量,从而实现与声明字段final相同的性能优化。与final字段相比,稳定值在初始化时间方面提供了更大的灵活性。这是一个预览 API。
稳定值具有以下特性:
class OrderController {
private final Logger logger = Logger.create(OrderController.class);
void submitOrder(User user, List<Product> products) {
logger.info("order started");
...
logger.info("order submitted");
}
}
由于 logger 是 OrderController 类的 final 字段,因此在创建 OrderController 实例时,必须立刻初始化该字段。这意味着创建新的 OrderController 可能会很慢,毕竟,获取日志记录器有时需要进行昂贵的操作,如读取和解析配置数据,或准备记录日志事件的存储空间。这种初始化工作不仅不利于应用程序的启动,而且可能没有必要。毕竟,有些组件可能永远都不需要记录事件,那么为什么要在前面做这些昂贵的工作呢?
由于这些原因,我们通常会尽可能推迟复杂对象的初始化时间,以便只在需要时才创建这些对象。我们可以将其初始化移到 getter 方法中。该方法会检查是否已经存在日志对象;如果不存在,则会创建一个新的日志对象,并将其存储在一个 logger 字段中。虽然这种方法可以改善应用程序的启动,但也有一些缺点:
我们可能会期望 JVM 通过对已初始化的 logger 字段进行常量折叠访问,或在 getLogger 方法中省略 logger == null 检查等方式来优化对 logger 字段的访问。遗憾的是,由于字段不再是 final,JVM 无法相信其内容在初始更新后永远不会改变。使用可变字段实现的灵活初始化并不高效。
简而言之,Java 语言允许我们控制字段初始化的方式要么太受约束,要么太不受约束。一方面,final字段受到的约束太强,需要在对象或类的生命周期早期进行初始化,这通常会降低应用程序的启动性能。另一方面,通过使用非final可变字段进行灵活初始化使得推理正确性变得更加困难。不变性和灵活性之间的紧张关系导致开发人员采用不完美的技术,这些技术无法解决根本问题,并导致代码更加脆弱且难以维护。
稳定值是一个对象,其类型为 StableValue,只保存一个数据值,即其内容。稳定值必须在首次检索其内容之前的一段时间初始化,此后将不可更改。稳定值是实现延迟不变性的一种方法。
有两种指定初始化的方式:
class OrderController {
// 在 getter 方法中指定初始化
private final StableValue<Logger> logger = StableValue.of();
Logger getLogger() {
// orElseSet方法保证提供的 lambda 表达式仅计算一次,即使logger.orElseSet(...)同时调用也是如此。
return logger.orElseSet(() -> Logger.create(OrderController.class));
}
// 在声明位置指定初始化
private final Supplier<Logger> logger
= StableValue.supplier(() -> Logger.create(OrderController.class));
void submitOrder(User user, List<Product> products) {
logger.get().info("order started");
...
logger.get().info("order submitted");
}
}
class Application {
static final List<OrderController> ORDERS
= StableValue.list(POOL_SIZE, _ -> new OrderController());
public static OrderController orders() {
long index = Thread.currentThread().threadId() % POOL_SIZE;
return ORDERS.get((int)index);
}
}
::: info JEP 503: Remove the 32-bit x86 Port
Remove the source code and build support for the 32-bit x86 port. This port was deprecated for removal in JDK 24 (JEP 501) with the express intent to remove it in a future release.
:::
移除32位x86端口的源代码和构建支持。该端口在JDK 24(JEP 501)中已被标记为弃用,明确计划在未来版本中移除。
::: info JEP 505: Structured Concurrency (Fifth Preview)
Simplify concurrent programming by introducing an API for structured concurrency. Structured concurrency treats groups of related tasks running in different threads as single units of work, thereby streamlining error handling and cancellation, improving reliability, and enhancing observability. This is a preview API.
:::
<br />
通过引入结构化并发 API 来简化并发编程。结构化并发将不同线程中运行的相关任务组视为单个工作单元,从而简化错误处理和取消,提高可靠性并增强可观测性。这是一个预览 API。
<br />
结构化并发
::: info JEP 506: Scoped Values
Introduce scoped values, which enable a method to share immutable data both with its callees within a thread, and with child threads. Scoped values are easier to reason about than thread-local variables. They also have lower space and time costs, especially when used together with virtual threads (JEP 444) and structured concurrency (JEP 505).
:::
引入作用域值,使方法能够与线程中的被调用方以及子线程共享不可变数据。作用域值比线程局部变量更容易推理。它们还具有较低的空间和时间成本,特别是当与虚拟线程(JEP 444)和结构化并发(JEP 505)一起使用时。
有一个小的更改:ScopedValue.orElse 方法不再接受 null 作为其参数。
作用域值
::: info JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)
Enhance pattern matching by allowing primitive types in all pattern contexts, and extend instanceof and switch to work with all primitive types. This is a preview language feature.
:::
通过允许在所有模式上下文中使用原始类型来增强模式匹配,并扩展 instanceof 和 switch 以使用所有原始类型。这是一个预览语言功能。
模式、instanceof 和 switch中的原始类型
::: info JEP 508: Vector API (Tenth Incubator)
Introduce an API to express vector computations that reliably compile at runtime to optimal vector instructions on supported CPUs, thus achieving performance superior to equivalent scalar computations.
:::
<br />
引入一个 API 来表达矢量计算,这些计算在运行时可靠地编译为受支持的 CPU 上的最佳矢量指令,从而实现优于等效标量计算的性能。
::: info JEP 509: JFR CPU-Time Profiling (Experimental)
Enhance the JDK Flight Recorder (JFR) to capture more accurate CPU-time profiling information on Linux. This is an experimental feature.
:::
增强 JDK 飞行记录器 (JFR) 以在 Linux 上捕获更准确的 CPU 时间分析信息。这是一个实验性功能。
::: info JEP 510: Key Derivation Function API
Introduce an API for Key Derivation Functions (KDFs), which are cryptographic algorithms for deriving additional keys from a secret key and other data.
:::
引入密钥派生函数(KDF)的 API,这是一种用于从密钥和其他数据派生其他密钥的加密算法。
::: info JEP 511: Module Import Declarations
Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself.
:::
通过简洁地导入模块导出的所有包的功能来增强 Java 编程语言。这简化了模块库的重用,但不要求导入代码本身必须在模块中。
::: info JEP 512: Compact Source Files and Instance Main Methods
Evolve the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large.
:::
发展 Java 编程语言,使初学者无需了解专为大型程序设计的语言功能,即可编写自己的第一个程序。初学者无需使用某种独立的语言变体,即可为单类程序编写简化的声明,然后随着技能的增长无缝扩展他们的程序以使用更高级的功能。经验丰富的开发者同样可以简洁地编写小型程序,而不必使用那些为大规模编程设计的结构。
简单说就是省略显式类声明和 public static 修饰符,简化输出语句,来简化入门代码和脚本开发。
void main() {
println("Hello Java 23!"); // 隐式调用 System.out.println
}
改动点:
IO.println("Hello, world!")
, 除非显式导入这些方法。System.out
和System.in
, 而不是java.io.Console
类。::: info JEP 513: Flexible Constructor Bodies
In the body of a constructor, allow statements to appear before an explicit constructor invocation, i.e., super(...) or this(...). Such statements cannot reference the object under construction, but they can initialize its fields and perform other safe computations. This change allows many constructors to be expressed more naturally. It also allows fields to be initialized before they become visible to other code in the class, such as methods called from a superclass constructor, thereby improving safety.
:::
在构造函数体内,允许在显式构造函数调用(即 super(...) 或 this(...))之前出现语句。这些语句不能引用正在构造的对象,但可以初始化其字段并执行其他安全计算。这一变化使许多构造函数能够更自然地表达。它还允许在字段对类中其他代码(如从超类构造函数调用的方法)可见之前对其进行初始化,从而提高安全性。
::: info JEP 514: Ahead-of-Time Command-Line Ergonomics
Make it easier to create ahead-of-time caches, which accelerate the startup of Java applications, by simplifying the commands required for common use cases.
:::
这项改进旨在简化创建 Java AOT(提前编译)缓存的命令,让普通开发者更容易使用这项高级技术,从而大幅缩短 Java 应用的启动时间。
在之前的 Java 版本中,创建 AOT 缓存非常复杂:
java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./app_cache.so -XX:SharedArchiveFile=./app_cached.jsa -Xshare:dump -cp myapp.jar com.example.MainClass
新版本简化了这个过程:
java -Xaot:force -jar myapp.jar
# 或者
java -Xaot:generate -jar myapp.jar
这项改进使得 Java 开发者能够通过简单的命令参数,就能获得类似原生编译语言的启动速度,同时保持 Java 的跨平台优势和运行时优化能力。这标志着 Java 在云原生时代的重要进化,让高性能 Java 应用的门槛大大降低。
::: info JEP 515: Ahead-of-Time Method Profiling
Improve warmup time by making method-execution profiles from a previous run of an application instantly available, when the HotSpot Java Virtual Machine starts. This will enable the JIT compiler to generate native code immediately upon application startup, rather than having to wait for profiles to be collected.
:::
当 HotSpot Java 虚拟机启动时,可立即从应用程序的上一次运行中获取方法执行配置文件,从而缩短预热时间。这将使 JIT 编译器能在应用程序启动时立即生成本地代码,而无需等待收集配置文件。
<br />
HotSpot JVM 刚启动时,所有字节码都运行在解释模式下,速度很慢。为了让热点方法(频繁调用的方法)达到最佳性能,JVM 必须经历以下阶段:
JEP 515 的思路可以概括为一句话:
“把上一次运行得到的剖析数据持久化到磁盘,下一次启动时直接加载。”
java -XX:+UseAOTMethodProfiles -XX:AOTProfilePath=./myapp.prof -jar myapp.jar
这项改进的本质是:将"学习成本"从运行时提前到构建时或第一次运行时,通过复用之前运行的经验来避免重复的学习过程。
就像一位经验丰富的司机:
传统方式:每次开车都要重新熟悉路况
新方式:使用之前的导航记录,一上路就知道最优路线
::: info JEP 518: JFR Cooperative Sampling
Improve the stability of the JDK Flight Recorder (JFR) when it asynchronously samples Java thread stacks. Achieve this by walking call stacks only at safepoints, while minimizing safepoint bias.
:::
提高 JDK Flight Recorder (JFR) 异步采样 Java 线程堆栈时的稳定性。为此,我们只在安全点处走查调用堆栈,同时尽量减少安全点偏差。
方案 | 做法 | 缺点 |
---|---|---|
Stop-the-world | 让所有线程进入 safepoint 后再采样 | 业务停顿(几十毫秒),破坏低延迟场景 |
冒险异步 | 直接爬栈,不做全局停顿 | 不稳定,可能 JVM 崩溃 |
_should_sample_at_safepoint
标志。JEP 518 把 “安全”与“低延迟” 从对立变为兼得 —— 线程自己走进安全点采样,既保证栈可信,又把停顿缩小到单线程级。
::: info JEP 519: Compact Object Headers
Change compact object headers from an experimental feature to a product feature.
:::
将紧凑对象头从实验功能改为产品功能。
Java 对象在堆中的存储包含对象头和实例数据。对象头又分为:
在 64 位 JVM 中,普通对象头通常占 12字节(96位) 至 16字节(128位)。对于许多平均大小仅为 32-64 字节的小对象来说,对象头的开销占比非常高,可能达到 20% 到 50%。JEP 450 通过以下方式将对象头压缩至 64 位 (8 字节):
为了更直观地理解其变化,可以参考下表对传统对象头与紧凑对象头进行的对比:
传统对象头大小
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。