本文聚焦 Java 25 中已永久化的 6 个特性:紧凑源文件与实例 main 方法、灵活的构造器主体、Scoped Values、模块导入声明、AOT 命令行易用性与方法剖析、分代 Shenandoah。通过简明说明与示例代码,帮助你快速把握其设计意图与落地用法。
1. 紧凑源文件与实例 main 方法
Java 25 支持“无显式类声明”的文件,并提供实例 main
方法与更短的 I/O API(java.lang.IO
),降低入门成本。
- 无需
class
声明,编译器会生成隐式、final、未命名类承载代码。 - 无需冗长的
System.out.println
,改用IO.println
。 - 自动导入
java.base
中常用类型(如集合/数学/时间)。
示例:
void main() {
IO.println("Hello, World!");
}
2. 灵活的构造器主体(Flexible Constructor Bodies)
以往构造器必须先调用 super()
或 this()
,才能执行校验或准备逻辑。Java 25 允许在不引用“正在构造的实例”的前提下,将校验逻辑放在显式父构造器调用之前,使代码更自然、更易读。
之前的常见写法:
class Employee extends Person {
Employee(String name, int age) {
super(name, age);
if (age < 18 || age > 67) {
throw new IllegalArgumentException("Age out of range");
}
}
}
class Employee extends Person {
Employee(String name, int age) {
super(name, verifyAge(age));
}
private static int verifyAge(int value) {
if (value < 18 || value > 67)
throw new IllegalArgumentException("Age out of range");
return value;
}
}
Java 25 的更清晰写法:
class Employee extends Person {
Employee(String name, int age) {
if (age < 18 || age > 67) {
throw new IllegalArgumentException("Age out of range");
}
super(name, age);
}
}
class BetterSub extends Super {
final int x;
BetterSub(int x) {
this.x = x;
super();
}
@Override void overriddenMethod() { System.out.println(x); }
}
3. Scoped Values
Scoped Values 是在结构化并发与虚拟线程场景下,传递“不可变上下文”的更合适机制。与 ThreadLocal
相比,它具有更清晰的词法作用域、更安全的不可变性以及更自然的并发传播语义。
关键点:
- 在
ScopedValue.where(...).run(...)
/call(...)
的作用域内绑定并使用,不可中途变更。 - 作用域之外派生的线程不会看到绑定,便于控制上下文生命周期。
示例(绑定请求上下文并在并发任务中使用):
public class RequestContext {
private final String requestId;
public RequestContext(String requestId) { this.requestId = requestId; }
public String requestId() { return requestId; }
}
public class ContextScope {
public static final ScopedValue<RequestContext> CONTEXT = ScopedValue.newInstance();
}
public class RequestHandler {
public void handleRequest(String rawRequestId) {
RequestContext ctx = new RequestContext(rawRequestId);
ScopedValue.where(ContextScope.CONTEXT, ctx).run(() -> {
try {
doWork();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
});
}
void doWork() throws InterruptedException {
try (var scope = new StructuredTaskScope<Void>()) {
scope.fork(this::taskA);
scope.fork(this::taskB);
scope.join();
}
}
void taskA() {
RequestContext ctx = ContextScope.CONTEXT.get();
System.out.println("taskA: requestId = " + ctx.requestId());
helper();
}
void taskB() {
RequestContext ctx = ContextScope.CONTEXT.get();
System.out.println("taskB: requestId = " + ctx.requestId());
}
void helper() {
RequestContext ctx = ContextScope.CONTEXT.get();
System.out.println("helper: requestId = " + ctx.requestId());
}
}
4. 模块导入声明(Module Import Declarations)
以模块维度一次性导入该模块导出的所有类型,减少样板代码并使依赖更直观。此机制是对现有导入方式的“补充”,并非替代,注意名称冲突与显式性降低的风险。
示例:
import module java.base
5. AOT 命令行易用性与方法剖析
两条 JEP 聚焦降低启动延迟与缩短 JIT 预热时间:
- 命令行易用性(JEP 514):引入
-XX:AOTCacheOutput=<file>
,内部生成并清理临时 AOT 配置文件,简化“记录+创建”的流程。 - 方法剖析(JEP 515):将训练运行中的方法级执行剖析融入 AOT 缓存,让生产环境的 JIT 以更好的初始知识起步。
示例(生成 AOT 缓存输出):
java -XX:AOTCacheOutput=aot.cache -cp app.jar com.example.Main
6. 分代 Shenandoah
将 Shenandoah 从“非分代模式”推进到“分代模式”以生产可用,便于更高效地处理不同生命周期的对象。默认仍为单代模式,可通过参数启用分代:
java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
小结
Java 25 的六大永久特性着力改善开发体验(更简洁的源文件、更自然的构造器写法、模块层级导入),并在并发上下文传递(Scoped Values)与启动性能优化(AOT 易用性、方法剖析)方面显著增强;分代 Shenandoah 则为 GC 带来更具针对性的性能潜力。这些改进共同指向“更易用、更高效、更现代”的 Java。