JDK 21 的 Record Patterns 支持多层嵌套 record 的直接解构,但要求每层均为 record 类型,不支持 class 或非 record 的 sealed 实现类;编译和运行需启用预览特性,且 IDE 和依赖需同步配置。

Record Patterns 在 JDK 21 中能直接解构多层嵌套 record,但前提是每一层都必须是 record 类型,且不能混用普通类或 sealed 接口实现类(除非该实现类本身也是 record)。
嵌套 record 解构的前提:所有层级都得是 record
Java 不允许在记录模式中对非 record 类型做字段级解构。比如 Rectangle(Point tl, Point br) 能解构,是因为 Rectangle 和 Point 都是 record;但如果 tl 是普通 class Point,instanceof Rectangle(Point(int x, int y), ...) 会编译失败。
-
record的字段访问器(如x())是 public、final、无副作用的,这是编译器生成安全解构逻辑的基础 - 哪怕只有一层用了
class或interface实现,就必须退回到手动调用 getter +instanceof判断的老路 - 使用
sealed接口配合 record 实现时,switch 中的 case 可以写Circle(double r),但这是“类型模式 + 记录模式”的组合,不是纯嵌套记录解构
在 instanceof 中一次性提取四层字段值
像 Organization(String name, Company company, String mission) 这种四级嵌套,只要每层都是 record,就能用一层 pattern 写完:
if (obj instanceof Organization(String orgName,
Company(String compName,
Person(String pName, int age,
Address(String street, String city, String zip)),
String industry),
String mission)) {
System.out.println(orgName + " → " + compName + " → " + pName + ", " + age);
}
注意几个实操细节:
- 变量名可以省略类型(用
var),但类型声明更清晰,尤其在字段名易混淆时(如多个name) - 编译器会自动插入 null 检查:如果中间某层为
null(如company为空),整个instanceof返回false,不会 NPE - 不能在 pattern 中写表达式,比如
Person(String name, int age + 1)是非法的
在 switch 表达式中按嵌套结构分支 dispatch
当你要根据嵌套字段值做不同处理(比如按城市分类地址、按行业分发公司任务),switch + 嵌套 Record Pattern 是最紧凑的写法:
String category = switch (obj) {
case Organization(_, Company(_, Person(_, _, Address(_, "Beijing", _)), _), _) -> "Beijing team";
case Organization(_, Company(_, Person(_, _, Address(_, "Shanghai", _)), _), _) -> "Shanghai team";
case Organization(String n, _, _) when n.startsWith("Global") -> "HQ";
default -> "other";
};
这里的关键点:
- 下划线
_表示忽略该字段,不绑定变量,比写var ignored更轻量 -
when子句可接任意布尔表达式,但只能放在整个 pattern 之后,不能插在中间 - 如果多个 case 的 pattern 结构相同但常量值不同(如不同城市),JVM 会优化成跳转表,性能接近 if-else 链
容易被忽略的兼容性与调试陷阱
Record Patterns 是 JDK 21 的预览特性(JEP 440),默认未启用;JDK 22 才转正(JEP 456)。这意味着:
- 编译需显式加参数:
javac --enable-preview --release 21 *.java - 运行也需加:
java --enable-preview Main,否则instanceof Point(int x, int y)会报语法错误 - IDE(如 IntelliJ 2025.3)可能默认不识别,需在项目 SDK 设置里勾选 “Enable preview features”
- 反编译字节码会看到
invokedynamic调用ObjectMethods.bootstrapRecordPattern,这不是你写的代码,别试图 debug 进去
真正麻烦的是混合旧代码:一旦你在同一模块里用了 Record Pattern,所有依赖它的 class 都得用 --enable-preview 编译,否则 NoClassDefFoundError 会出现在运行时,而不是编译期。

















