unnamed variables 是 jdk 21 的正式特性(jep 443),无需预览参数即可直接使用单个下划线 _ 作为形参、局部变量、catch 参数等位置的忽略占位符,但不可用于字段或返回类型,且 _ 不可赋值后读取或自增。

Unnamed_Variables 是 JDK 21 的正式特性,不是预览或实验功能
从 JDK 21 开始,Unnamed_Variables 已作为标准语言特性启用(JEP 443),无需额外启动参数。你只要用 JDK 21+ 编译和运行,就能直接使用下划线 _ 作为形参、局部变量、catch 参数等位置的“忽略占位符”。
注意:它**不能用于字段(成员变量)或方法返回类型**,也不支持多个连续下划线(如 __)——只有单个 _ 合法。
在 lambda、方法参数、for-each 中用 _ 替代无用变量名
常见场景是 lambda 表达式里只关心元素索引或键,不关心值本身;或者遍历时只需触发副作用,无需绑定变量。
- lambda 形参:
list.forEach(_ -> System.out.println("processed")); - 增强 for 循环:
for (String _ : strings) { logAccess(); } - 方法参数(接口实现):
Consumer<string> c = _ -> doSomething();</string> - record 模式匹配(JDK 21+)中也可用于嵌套解构:
case Point(int x, int _) -> x * x;
编译器会明确拒绝把 _ 当作普通标识符使用——比如 int _ = 42; 在 JDK 21 是合法的,但 _++ 或 System.out.println(_); 会报错:error: cannot reference an unassigned variable。
catch 块中用 _ 忽略异常对象本身
当你只需要捕获异常并统一处理(比如记录日志后静默吞掉),又不想声明一个永远不会被读取的变量名时,可以直接写:
try {
riskyOperation();
} catch (IOException _) {
logger.warn("IO failed, ignored");
}
这比 catch (IOException e) { ... } 更清晰地表达了“我不要这个异常实例”,也避免了 IDE 提示 “variable 'e' is never read”。
但要注意:_ 在 catch 中仍参与异常类型检查和多异常捕获语法,例如:catch (IOException | SQLException _) {...} 是合法的;而 catch (_) {...}(无类型)则非法。
容易踩的坑:IDE 和构建工具可能未同步识别
即使用了 JDK 21,IntelliJ 或 Eclipse 若项目语言级别没设对,仍会标红 _ 并提示“invalid identifier”。检查以下三点:
- 确保 Maven/Gradle 的
source和target显式设为21(不能只靠 JAVA_HOME) - IDE 中模块 SDK 和 language level 都要选 “21”(IntelliJ:File → Project Structure → Project / Modules)
- 旧版 Lombok(≤1.18.30)与
_冲突,会误判为字段名导致编译失败;升级到 ≥1.18.32 即可
最隐蔽的问题是:某些静态分析工具(如 older versions of SpotBugs)会把 _ 当作弱命名警告。这不是语法错误,但会影响 CI 流水线通过——得在规则中显式禁用 MS_MUTABLE_COLLECTION_PKGPROTECT 类相关检查。










