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 创建结构化的业务处理模型
相关推荐
枫叶V2 小时前
Go 实现大文件分片上传与断点续传
后端·go
福大大架构师每日一题2 小时前
2025-09-12:删除元素后 K 个字符串的最长公共前缀。用go语言,给定一个字符串数组 words 和一个整数 k。对于数组中每个位置 i,先把下标为 i
后端
卸任2 小时前
Electron运行环境判断(是否在虚拟机中)
前端·react.js·electron
叫我詹躲躲2 小时前
前端竟能做出这种专业医疗工具?DICOM Viewer 医学影像查看器
前端·javascript·vue.js
ze_juejin2 小时前
为什么说vue比Angular轻巧
前端
子兮曰2 小时前
🚀彻底掌握异步编程:async/await + Generator 深度解析与20个实战案例
前端·javascript·typescript
Python私教2 小时前
Django全栈班v1.01 Python简介与特点 20250910
后端·python·django
六月的可乐2 小时前
Vue3项目中集成AI对话功能的实战经验分享
前端·人工智能·openai
PineappleCoder2 小时前
面试官你好,请您听我“编解”!!!
前端·算法·面试