Record模式匹配是JDK21解决嵌套数据解构痛点的刚需工具,可一步完成类型检查与多层字段提取,避免instanceof+强转+getter的三段式冗余;支持基础解构、常量匹配、嵌套解构及sealed类switch匹配,兼具安全、简洁与编译期校验优势。

Record 模式匹配在 JDK 21 中不是“锦上添花”,而是解决嵌套数据解构痛点的刚需工具——它能一步完成类型检查 + 多层字段提取,避免 instanceof 后手动强转、再调用 getter 的三段式冗余写法。
record instanceof 解构:最常用但容易漏掉 var 和常量匹配
基础解构看似简单,但实际写错率很高。比如你有 record Point(int x, int y) {},下面这三种写法语义完全不同:
-
if (obj instanceof Point(int x, int y)):要求obj是Point类型,且声明两个新变量x、y(类型必须显式写出) -
if (obj instanceof Point(var x, var y)):更推荐,类型由编译器推导,避免重复写int;var在此处是合法的,且作用域仅限于该if块内 -
if (obj instanceof Point(10, var y)):带常量匹配,只对x == 10的实例生效,y仍被提取。这在过滤特定结构时比if (p.x() == 10)更安全(不触发 NPE)
常见错误是写成 if (obj instanceof Point p) 后再写 p.x() —— 这就完全没用上模式匹配,白丢了类型安全和解构能力。
嵌套 record 解构:一层括号对应一层 record 结构
当你面对类似 record WindowFrame(Point origin, Size size) {} 和 record Size(int width, int height) {} 这类组合时,嵌套解构不是“套娃”,而是按字段层级严格展开:
想直接拿到 origin.x 和 size.height?写成这样就行:
if (frame instanceof WindowFrame(Point(int x, int y), Size(int w, int h))) {
System.out.println("x=" + x + ", height=" + h);
}
注意三点:
- 括号必须成对:外层
WindowFrame(...),里面每个字段若也是 record,就得各自加括号,不能省略 - 字段顺序必须与 record 定义一致,错一个位置就编译失败(不是运行时异常)
- 中间任意一层为
null时,整个instanceof判断直接返回false,不会抛NullPointerException—— 这是模式匹配的安全保障,不用提前判空
switch 表达式中结合 sealed class 使用:处理多态数据结构
纯 record 解构适合“已知类型”的场景;一旦涉及多种可能类型(比如几何图形),就要配合 sealed 接口和 switch:
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double length, double width) implements Shape {}
Shape s = new Circle(3.0);
String desc = switch (s) {
case Circle(double r) -> "circle with r=" + r;
case Rectangle(double l, double w) -> "rect " + l + "x" + w;
};
关键点:
-
sealed接口强制限定所有子类型,编译器能确保switch覆盖全部分支,无需default(除非你主动加) - 每个
case后的括号里写的是该 record 的字段模式,不是构造器调用语法 - 如果某 record 字段本身又是 record(比如
record ColoredShape(Shape shape, Color color) {}),照样可以继续嵌套:case ColoredShape(Circle(double r), Color c)
性能与兼容性边界:别在 record 模式里做计算或副作用
record 模式匹配本质是编译期生成的类型检查 + 字段读取,几乎零运行时开销。但有两处容易踩坑:
- 模式中不能出现方法调用或表达式,比如
Point(x > 0 ? x : 0, y)是非法的 —— 括号内只接受类型声明、var或字面量 - JDK 21 默认启用该特性,但需确认编译参数含
--enable-preview,否则报错illegal start of type;JDK 22 已转正,不再需要 preview 标志 - record 字段名变更会直接破坏所有依赖该字段名的模式(比如把
Point(int x, int y)改成Point(int px, int py)),所有instanceof Point(int x, int y)全部编译失败 —— 这既是约束,也是 API 稳定性的提示
真正复杂的地方不在语法嵌套深度,而在于字段命名是否足够稳定、sealed 层级是否收敛。一旦 record 结构开始频繁变动,模式匹配反而会成为编译期故障点。

















