Skip to main content

JDK 25 LTS

  • 预计 GA(正式发布)时间:2025-09-16(按 OpenJDK 半年节奏与公开计划),自 2021 年起,Java 采用“半年一更”的固定节奏,且每两年提供一个 LTS 版本(JDK 17 → 21 → 25)。LTS 面向企业生产,强调长期稳定与生态一致性。
为了迎接 JDK 25 LTS,本文先聚焦一个升级中最容易统一、最能减样板的语法改进:未命名变量与未命名模式(JEP 456/443)。 在日常 Java 编码中,我们经常为了“占位置”而硬起一个不会使用的名字,比如 ignoredunuseddummy。自 JDK 22 起,Java 将这种意图提升为一等公民:使用下划线 _ 声明“未命名变量(Unnamed Variables)”与“未命名模式(Unnamed Patterns)”,直接、明确地表达——“我不关心它”。 本文基于 JEP 443(JDK 21 Preview)与 JEP 456(JDK 22 Final)梳理该特性,给出可直接上手的示例与踩坑提示。

为什么需要未命名变量 / 模式

  • 明确表达意图:相比起随手起名 ignored_ 更清晰,也避免误用。
  • 消除样板代码:减少无意义的局部名与模式变量绑定,代码更紧凑。
  • 统一写法:与多语言生态(如 Scala、Kotlin、Python)中“占位符”习惯对齐,降低心智负担。

能做什么(Allowed)

未命名变量可以出现在“声明局部变量”的位置,但不会在作用域内引入可引用的名字:
  • catch 子句的异常参数
  • try-with-resources 的资源变量
  • lambda 的形参
  • 增强 for-each 的循环变量
  • 其他局部变量声明(只要之后不需引用该名字)
未命名模式可用于模式匹配中忽略不关心的组件:
  • 记录(Record)解构的某些组件
  • instanceof / switch 的模式匹配(含嵌套、守卫 when)

上手示例(变量)

  1. 不关心异常对象
try {
    riskyOperation();
} catch (IOException _) { // 明确:不关心异常对象本身
    handleError();
}
  1. 不关心资源变量(但仍需自动关闭)
try (var _ = Files.newInputStream(Path.of("/tmp/data.bin"))) {
    // 使用外部 API、日志等;无需引用资源变量名
    process();
}
  1. lambda 里参数未使用
// 单参未使用
list.forEach(_ -> log.debug("visited"));

// 多参未使用其一
map.forEach((key, _) -> handle(key));

// 多个参数都不使用也可
BiConsumer<String, Integer> noop = (_, _) -> {};
  1. 增强 for 不关心元素值
for (Order _ : orders) {
    metrics.increment();
}
提示:经典 for 计数循环通常需要在条件与自增中“引用”计数变量名,因此不能用 _(见下文限制)。

上手示例(模式)

  1. 记录解构时忽略不需要的组件
record Point(int x, int y, int z) {}

if (obj instanceof Point(int x, int y, _)) {
    use(x, y); // 忽略 z
}
  1. switch 模式匹配只取关心字段
record User(String name, int age, String email, boolean verified) {}

switch (user) {
    case User(var name, _, _, true) -> welcome(name);
    case User(_, var age, _, false) when age < 18 -> requireGuardian();
    default -> audit(user);
}
  1. 组合、嵌套模式
sealed interface Shape permits Circle, Rectangle {}
record Circle(double r, String color) implements Shape {}
record Rectangle(double w, double h, String color) implements Shape {}

String describe(Shape s) {
    return switch (s) {
        case Circle(double r, _) -> "circle r=" + r;
        case Rectangle(double w, double h, _) -> "rect " + w + "x" + h;
    };
}

重要限制(Don’ts)

  • 不能引用 _:未命名变量不会在作用域中引入可用名字,对其读/写都会是编译期错误。
    • 例如以下写法非法:
      • for (int _ = 0; _ < 10; _++) {}(条件、自增都在“引用” _
      • System.out.println(_)_ = 1
  • 仅可用于“声明/绑定”的位置:如 catch 参数、lambda 参数、资源变量、增强 for 元素变量、记录模式位等。
  • 可在同一作用域出现多次:多个 _ 不会互相“重名”,因为它们根本不引入名字。
  • _ 仍是保留标识:自 Java 9 起 _ 不是普通标识符,不能用作字段名、方法名等,仅在上述语境下具备“未命名”语义。

何时该用 / 何时不该用

  • 该用:
    • 确认值确实无关紧要,且使用 _ 能提升可读性时(如 catchlambda 未用参数、记录模式中个别字段)。
    • 仅需触发语义副作用但不用引用变量名(如 try-with-resources 的自动关闭)。
  • 不该用:
    • 读者可能需要该值来理解逻辑时,过度隐藏会降低可维护性。
    • 经典 for 计数、需要引用变量名的位置。

版本与状态

  • JEP 443(JDK 21,Preview):Unnamed Patterns and Variables(预览)。
  • JEP 456(JDK 22,Final):Unnamed Variables & Patterns(定稿并默认启用)。

小结

_ 是“我不关心”的显式承诺。 它让 Java 代码更简洁、更一致,又避免“明明起了名却没用”的误导。理解其适用位置与“不可引用”的限制,就能放心把样板名换成更有表现力的 _

参考