Java 21 switch 模式匹配实战:sealed 接口 + record 替代 if-instanceof 链

Java 21 switch 模式匹配实战:sealed 接口 + record 替代 if-instanceof 链

处理一族类型时,你写过多少这样的代码?if (shape instanceof Circle c) { ... } else if (shape instanceof Rectangle r) { ... } else if ...。分支一多就成了又臭又长的判断链,新增类型时编译器还不提醒你哪里漏了处理。Java 21 把 switch 模式匹配(JEP 441)转正,配合 sealed 接口和 record,能把这类代码写得又短又安全,漏一个分支直接编译报错。这篇用一个几何图形的例子讲透。

老写法:instanceof 链的三个痛点

先看没有模式匹配时的典型写法:

java 复制代码
interface Shape {}
record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double base, double height) implements Shape {}

double area(Shape shape) {
    if (shape instanceof Circle) {
        Circle c = (Circle) shape;              // 还得手动强转
        return Math.PI * c.radius() * c.radius();
    } else if (shape instanceof Rectangle) {
        Rectangle r = (Rectangle) shape;
        return r.w() * r.h();
    } else if (shape instanceof Triangle) {
        Triangle t = (Triangle) shape;
        return 0.5 * t.base() * t.height();
    }
    throw new IllegalArgumentException("未知图形: " + shape);
}

痛点有三:每个分支都要手动强制转型;分支之间没有约束,漏写一个类型编译器一声不吭,只能运行时抛异常;代码噪音大,真正的业务(算面积)被样板代码淹没。

第一步:用 sealed 封死类型集合

sealed 关键字(Java 17 转正)让你显式声明「哪些类型可以实现这个接口」。这一步是模式匹配能做穷尽性检查的前提:

java 复制代码
sealed interface Shape permits Circle, Rectangle, Triangle {}

record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double base, double height) implements Shape {}

permits 列出的三个就是 Shape全部 实现,编译器由此知道这是一个封闭集合。record 则自动生成构造器、radius() 这类访问器和 equals,做数据载体正合适。

第二步:switch 模式匹配,强转全省了

有了 sealed,switch 就能直接对类型分支,并自动把匹配到的对象绑定到一个变量,不用再强转:

java 复制代码
double area(Shape shape) {
    return switch (shape) {
        case Circle c    -> Math.PI * c.radius() * c.radius();
        case Rectangle r -> r.w() * r.h();
        case Triangle t  -> 0.5 * t.base() * t.height();
    };
}

注意这里没有 default 分支 ,却能编译通过。因为 Shape 是 sealed 的,编译器确认三个 case 已经覆盖了所有可能的类型------这就是穷尽性(exhaustiveness)。它的价值在下一节。

sealed + switch 的杀手锏:漏分支编译不过

假设某天团队新增了一种图形:

java 复制代码
sealed interface Shape permits Circle, Rectangle, Triangle, Square {}
record Square(double side) implements Shape {}

只要你没在 area 的 switch 里补上 case Square,编译立刻失败:

复制代码
error: the switch statement does not cover all possible input values

这就是它比 instanceof 链强的核心:新增类型时,编译器会揪出每一处需要更新的 switch ,而不是等到线上跑出 IllegalArgumentException 才发现。类型安全从运行时提前到了编译期。

record 解构:直接把字段拆出来

Java 21 的模式匹配还支持 record 解构(record patterns),可以在 case 里直接把 record 的字段绑定成变量,连访问器都省了:

java 复制代码
double area(Shape shape) {
    return switch (shape) {
        case Circle(double r)        -> Math.PI * r * r;
        case Rectangle(double w, double h) -> w * h;
        case Triangle(double b, double h)  -> 0.5 * b * h;
        case Square(double s)        -> s * s;
    };
}

when 守卫:同一类型再按条件细分

有时同一类型要根据取值走不同逻辑,用 when 加一个布尔守卫即可,比嵌套 if 清爽得多:

java 复制代码
String describe(Shape shape) {
    return switch (shape) {
        case Circle c when c.radius() > 100 -> "超大圆";
        case Circle c                       -> "普通圆";
        case Rectangle(double w, double h) when w == h -> "正方形(其实是矩形)";
        case Rectangle r                    -> "矩形";
        default -> "其他图形";
    };
}

注意顺序:带 when 的分支要放在同类型的无条件分支前面,否则无条件分支会先兜住,守卫永远命中不了------编译器也会对这种「被遮蔽」的 case 报错,算是又帮你兜了一层。

别忘了处理 null

传统 switch 遇到 null 会直接抛 NullPointerException。Java 21 允许显式写 case null,把空值也纳入统一处理,不用在 switch 外面再包一层判空:

java 复制代码
String safeDescribe(Shape shape) {
    return switch (shape) {
        case null        -> "空图形";
        case Circle c    -> "圆";
        default          -> "其他";
    };
}

小结

  • sealed 接口封死类型集合,是 switch 做穷尽性检查的前提;record 做不可变数据载体。
  • Java 21 的 switch 模式匹配自动完成类型匹配与变量绑定,彻底告别手动强转和 instanceof 链。
  • 最大价值是编译期穷尽性:sealed 类型下漏写分支直接编译失败,新增类型时编译器帮你定位所有要改的地方。
  • record 解构直接拆字段,when 守卫按条件细分,case null 统一处理空值。

一句话记忆:sealed 定义「就这几种类型」,switch 模式匹配保证「每种都处理到」------漏一个,编译器不放你过。

相关推荐
凤山老林6 分钟前
聊聊企业级 API 安全:Spring Boot 落地 OAuth 2.1、mTLS 与接口签名防篡改
spring boot·后端·安全·oauth
米小虾7 分钟前
把 KV Cache 从 3514 字节压到 890 字节:DeepSeek V4.1-Flash 动了什么,又没动什么
人工智能
锋行天下10 分钟前
LangGraph 进阶:Command + Send 动态控制流、并行 Map-Reduce 实战与踩坑
人工智能
土司大王15 分钟前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
米小虾17 分钟前
AI 观察:CEO 们集体喊"慢一点",钱却在加速进场
人工智能
微三云生态系统架构师-彭丹31 分钟前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
颜颜yan_32 分钟前
ESP-IDF 鸿蒙 PC 适配全记录:打通 Python、构建工具链与 ESP32-P4 固件生成
python·华为·harmonyos
言乐636 分钟前
Python加速器4跨境网络加速器
运维·服务器·开发语言·网络·python
土司大王37 分钟前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
weixin_4407305043 分钟前
线程02-并发串行-互斥锁-Semaphore-Event
python·thread