186. Java 模式匹配 - Java 21 新特性:Record Pattern(记录模式匹配)

186. Java 模式匹配 - Java 21 新特性:Record Pattern(记录模式匹配)

Java 在 SE 16 中引入了 record(记录类)作为简洁表示不可变数据的方式。而在 Java 21 ,记录又进化了一个层次------引入了 Record Pattern(记录模式匹配)

这意味着我们可以直接在 ifswitch 中解构 record 类型,提取其中的字段,写出更干净、更具表达力的代码。


✅ 回顾:什么是 Record?

java 复制代码
public record Point(int x, int y) {}

等价于一个包含:

  • 两个字段 xy
  • 对应的访问器 x()y()
  • 自动生成的构造函数和 equals()hashCode()toString() 方法

🎯 什么是记录模式(Record Pattern)?

记录模式允许你使用结构匹配语法,直接从 record解构并提取字段

🌰 示例:基本模式匹配

java 复制代码
Object o = new Point(3, 4);

if (o instanceof Point(int x, int y)) {
    System.out.println("x = " + x + ", y = " + y);
}

✨ 说明:

  • o instanceof Point(int x, int y) 不只是判断 oPoint,还将其解构为 xy
  • xy 是自动绑定的局部变量

🧠 深入理解:记录模式的行为规则

✅ 1. 使用的是"规范构造函数"

  • record 可以声明多个构造函数
  • 但记录模式始终基于那个由编译器自动生成的"规范构造函数"
java 复制代码
record Point(int x, int y) {
    Point(int x) {
        this(x, 0);
    }
}

下面这段代码无法编译:

java 复制代码
Object o = ...;
// ❌ 不合法:没有 Point(int) 这种结构可匹配
if (o instanceof Point(int x)) {}

✅ 2. 你可以使用 var 做类型推断

java 复制代码
record Point(double x, double y) {}

Object o = new Point(1.1, 2.2);

if (o instanceof Point(var x, var y)) {
    System.out.println("类型被推断为 double: " + x + ", " + y);
}

✅ 3. 记录模式可以嵌套!

你可以在一个 record 中匹配另一个 record。

java 复制代码
record Point(double x, double y) {}
record Circle(Point center, double radius) {}

Object o = new Circle(new Point(1.0, 2.0), 5.0);

if (o instanceof Circle(Point(var x, var y), var radius)) {
    System.out.printf("圆心:(%f, %f), 半径:%f%n", x, y, radius);
}

💡 嵌套记录的结构匹配就像解包"洋葱层"。


✅ 4. 可与 switch 配合使用

java 复制代码
record Box(Object o) {}

Object o = new Box("hello");

String result = switch (o) {
    case Box(String s)  -> "字符串:" + s;
    case Box(Integer i) -> "整数:" + i;
    default             -> "其他类型";
};
System.out.println(result);

⚠️ 注意事项与坑点提醒

❌ 不支持装箱/拆箱转换

java 复制代码
record Point(Integer x, Integer y) {}

Object o = new Point(1, 2);

// ❌ 无法将 Integer 自动解构为 int
if (o instanceof Point(int x, int y)) {
}

你必须匹配 相同类型,不能依赖自动装箱/拆箱。


❌ 不支持不可能的类型匹配

java 复制代码
record Box(CharSequence o) {}

Object o = new Box("Java");

// ❌ Integer 不是 CharSequence 的子类,编译报错
switch (o) {
    case Box(String s)  -> System.out.println("字符串:" + s);
    case Box(Integer i) -> System.out.println("整数:" + i);
    default             -> System.out.println("其他类型");
}

⚠️ 所有模式类型必须是组件类型的 子类型或相同类型,否则编译错误。


🔥 补充实战场景

🎨 构建坐标系统中的图形识别

java 复制代码
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}

Object shape = new Rectangle(new Point(0, 0), new Point(10, 10));

if (shape instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) {
    System.out.printf("矩形范围:(x1=%d, y1=%d) 到 (x2=%d, y2=%d)%n", x1, y1, x2, y2);
}

🧾 小结

功能 描述
✅ 记录模式 支持 record 的结构解构和字段绑定
📦 类型推断 支持 var 自动推断字段类型
🧱 支持嵌套 可用于深层嵌套的记录结构
💥 类型安全 匹配的类型必须是字段的子类型或相同类型
⚠️ 限制 不支持装箱/拆箱,不支持非规范构造函数结构匹配

🎓 建议练习

  • 尝试用记录模式重写你的 DTO 判断逻辑
  • 编写带嵌套记录结构的 switch 分支逻辑
  • 结合 sealed class + record pattern 创建结构化的业务处理模型
相关推荐
子兮曰20 小时前
OpenClaw入门:从零开始搭建你的私有化AI助手
前端·架构·github
Victor35620 小时前
https://editor.csdn.net/md/?articleId=139321571&spm=1011.2415.3001.9698
后端
吴仰晖20 小时前
使用github copliot chat的源码学习之Chromium Compositor
前端
1024小神20 小时前
github发布pages的几种状态记录
前端
Victor35620 小时前
Hibernate(89)如何在压力测试中使用Hibernate?
后端
灰子学技术1 天前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
不像程序员的程序媛1 天前
Nginx日志切分
服务器·前端·nginx
Daniel李华1 天前
echarts使用案例
android·javascript·echarts
北原_春希1 天前
如何在Vue3项目中引入并使用Echarts图表
前端·javascript·echarts
JY-HPS1 天前
echarts天气折线图
javascript·vue.js·echarts