> ## Documentation Index
> Fetch the complete documentation index at: https://blog.pig4cloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JDK 25 来了，一个下划线解决所有「我不想起变量名」的痛苦

> 基于 JEP 456/JEP 443，系统讲解 Java 未命名变量与未命名模式的语义、适用场景、限制与最佳实践，并给出高质量示例。

### JDK 25 LTS

* 预计 GA（正式发布）时间：2025-09-16（按 OpenJDK 半年节奏与公开计划），自 2021 年起，Java 采用“半年一更”的固定节奏，且每两年提供一个 LTS 版本（JDK 17 → 21 → 25）。LTS 面向企业生产，强调长期稳定与生态一致性。

为了迎接 JDK 25 LTS，本文先聚焦一个升级中最容易统一、最能减样板的语法改进：未命名变量与未命名模式（JEP 456/443）。

在日常 Java 编码中，我们经常为了“占位置”而硬起一个不会使用的名字，比如 `ignored`、`unused`、`dummy`。自 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. 不关心异常对象

```java theme={null}
try {
    riskyOperation();
} catch (IOException _) { // 明确：不关心异常对象本身
    handleError();
}
```

2. 不关心资源变量（但仍需自动关闭）

```java theme={null}
try (var _ = Files.newInputStream(Path.of("/tmp/data.bin"))) {
    // 使用外部 API、日志等；无需引用资源变量名
    process();
}
```

3. `lambda` 里参数未使用

```java theme={null}
// 单参未使用
list.forEach(_ -> log.debug("visited"));

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

// 多个参数都不使用也可
BiConsumer<String, Integer> noop = (_, _) -> {};
```

4. 增强 for 不关心元素值

```java theme={null}
for (Order _ : orders) {
    metrics.increment();
}
```

提示：经典 `for` 计数循环通常需要在条件与自增中“引用”计数变量名，因此不能用 `_`（见下文限制）。

### 上手示例（模式）

1. 记录解构时忽略不需要的组件

```java theme={null}
record Point(int x, int y, int z) {}

if (obj instanceof Point(int x, int y, _)) {
    use(x, y); // 忽略 z
}
```

2. `switch` 模式匹配只取关心字段

```java theme={null}
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);
}
```

3. 组合、嵌套模式

```java theme={null}
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 起 `_` 不是普通标识符，不能用作字段名、方法名等，仅在上述语境下具备“未命名”语义。

### 何时该用 / 何时不该用

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

### 版本与状态

* JEP 443（JDK 21，Preview）：Unnamed Patterns and Variables（预览）。
* JEP 456（JDK 22，Final）：Unnamed Variables & Patterns（定稿并默认启用）。

### 小结

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

### 参考

* [JEP 456: Unnamed Variables & Patterns（JDK 22）](https://openjdk.org/jeps/456)
* [JEP 443: Unnamed Patterns and Variables（JDK 21 Preview）](https://openjdk.org/jeps/443)
* [The Java Language Specification（相关章节）](https://docs.oracle.com/javase/specs/)
