JEP 502,稳定值(预览版),在 JDK 25 中已移动到完成状态。这个 JEP 以前称为计算常量(预览版),它引入了计算常量的概念,被定义为最多初始化一次的不可变值持有者。新的 API 允许开发人员创建具有“延迟不可变性”的对象。这些对象可以在执行过程中的任何时候被初始化一次,然后保持不可变性,结合了 final 字段的性能优势和延迟初始化的灵活性。
稳定值 API 专门针对由复杂对象过早初始化而引起的应用程序启动性能问题。与必须在构造或类初始化期间初始化的 final 字段不同,稳定值可以按需初始化,同时还启用了 JVM 常量折叠优化。这些优化通常只适用于 final 字段。不过这仍然是一个预览功能。
稳定值 API 围绕StableValue类展开,该类持有一个只能精确设置一次的数据值。主要的初始化方法orElseSet()可确保即使在并发访问 的情况下也能进行线程安全的至多一次初始化:
class OrderController {
private final StableValue<Logger> logger = StableValue.of();
Logger getLogger() {
return logger.orElseSet(() -> Logger.create(OrderController.class));
}
}
复制代码
这种方法消除了与传统延迟初始化模式相关的常见陷阱。如果没有稳定的值,开发人员通常会使用带有 null 检查的可变字段,这会阻碍 JVM 优化,并会引入线程安全问题:
// 传统方法 - 失去了优化机会
class OrderController {
private Logger logger = null; // 可变字段
Logger getLogger() {
if (logger == null) {
logger = Logger.create(OrderController.class);
}
return logger;
}
}
复制代码
API 不能扩展了基本的稳定值,还包括稳定的供应商(supplier)和稳定的列表(list)。稳定的供应商允许在声明时指定初始化逻辑,同时延迟实际执行:
class DataService {
private final Supplier<DatabaseConnection> connection = StableValue.supplier(() -> new DatabaseConnection("jdbc:postgresql://localhost/db"));
void performQuery() {
DatabaseConnection db = connection.get(); // 数据库连接仅在首次访问时创建
}
}
复制代码
稳定列表支持集合,其中各个元素在访问时单独初始化:
class ThreadPool {
private final List<WorkerThread> workers = StableValue.list(POOL_SIZE, index -> new WorkerThread(index));
WorkerThread getWorker(int index) {
return workers.get(index); // 仅在首次访问时创建工作线程
}
}
复制代码
稳定值的关键优势在于 JVM 处理它们的方式。在底层,稳定值使用 JDK 内部的 @Stable 注解,它告诉 JVM,尽管存储在非 final 字段中,但值在初始更新后不会改变。这使得 final 字段可以使用相同的常量折叠优化。
稳定值使得从根本上重新考虑应用程序的初始化策略成为可能。现在,应用程序可以将昂贵组件的创建推迟到真正需要时,从而显著改善了启动时间:
class Application {
static final StableValue<OrderController> orders = StableValue.of();
static final StableValue<UserService> users = StableValue.of();
public static OrderController getOrderController() {
return orders.orElseSet(OrderController::new);
}
}
复制代码
这种模式允许应用程序立即启动,并根据应用程序的执行路径需要按需初始化组件。这种方法特别适用于具有大量组件的大型企业应用程序,其中许多组件在典型的执行过程中可能不会被使用。
作为一个预览 API,稳定值需要在编译和运行时显式启用:
javac --release 25 --enable-preview MyApplication.java
java --enable-preview MyApplication
复制代码
预览状态允许开发团队在最终确定 API 设计和实现之前,从 Java 社区收集反馈。
Java 25 中的稳定值 API 为长期存在的初始化挑战提供了一个引人注目的解决方案,它为开发人员提供了一个工具,将不可变字段的安全和性能与延迟初始化的灵活性结合了起来。
原文链接:
https://www.infoq.com/news/2025/06/java25-stable-values-api-startup/
评论