switch 按类型匹配Java 21 一行干掉 if-else 强转链系列Java 后端实战精通营 · 作者鱼宵配套课程仓库https://gitee.com/j67mk2/java21-journey 第 5 课先看一段越长越不敢动的代码支付路由每个后端都写过。微信、支付宝、银行卡……每加一种支付方式if-else链就加一层每个分支都是老三样instanceof 判断 手动强转 接 else。等你写到第五种支付方式这段代码已经长到没人敢重构了——动一行怕碰坏其它分支。而且类型转错一个线上直接ClassCastException。Java 21 的模式匹配 switch就是来终结这种写法的。今天用支付路由这个真实场景把老写法 vs 新写法逐行对照再讲透when守卫、yield和不用写 default背后的穷尽性。一句话结论switch 从比等值升级成按类型匹配 自动转型模式匹配 switchJEP 441JDK 21 正式特性case后面可以直接写类型 变量名匹配上就自动转型并绑定变量——一行顶以前判断 强转 绑定三行。类比快递站分拣。老写法是人工分拣每件包裹拆开看一眼instanceof、贴标签强转、再送传送带新写法是分拣机直接看面单品类传送带自动启动——判断、转型、绑定一步到位。关键代码同一笔支付路由老写法 vs 新写法完整可运行先看检查依据——一个 sealed 密封支付家族上一课学的 sealed 在这里派上大用场/** 密封支付家族permits 名单就三家这是 switch 能穷尽的底气 */publicsealedinterfacePaymentpermitsWeChat,Alipay,BankCard{longcents();// 金额单位分}recordWeChat(StringopenId,longcents)implementsPayment{}recordAlipay(StringtradeNo,longcents)implementsPayment{}recordBankCard(StringcardNo,longcents)implementsPayment{}老写法if-else instanceof 链staticStringrouteOld(Objectpayment){if(paymentnull){return支付方式不能是 null;}elseif(paymentinstanceofWeChat){WeChatw(WeChat)payment;// 手动强转转错就是 ClassCastExceptionreturn微信支付w.openId()w.cents()/100.0 元;}elseif(paymentinstanceofBankCard){BankCardb(BankCard)payment;if(b.cents()100000){// 守卫逻辑只能手写 if 嵌进去return银行卡大额支付b.cardNo()b.cents()/100.0 元需人工审核;}return银行卡普通支付b.cardNo()b.cents()/100.0 元;}else{thrownewIllegalStateException(未知支付方式payment.getClass());}}新写法模式匹配 switch同一个需求staticStringrouteNew(Paymentpayment){returnswitch(payment){caseWeChatw-微信支付w.openId()w.cents()/100.0 元;caseAlipaya-支付宝a.tradeNo()a.cents()/100.0 元;caseBankCardb when b.cents()100000-{// when 守卫子句先认类型再按金额细分doubleyuanb.cents()/100.0;yield银行卡大额支付b.cardNo()yuan 元需人工审核;}caseBankCardb-银行卡普通支付b.cardNo()b.cents()/100.0 元;casenull-支付方式不能是 null;};}这段代码讲什么四句话case WeChat w -一行同时完成判断类型 自动转型 绑定变量后面直接当WeChat用。老写法的instanceof 强转两行在这里一笔勾销。case BankCard b when b.cents() 100000when 守卫子句——同一个类型再按值细分分支。1000 元以上的银行卡走大额人工审核剩下的自然落到下面普通分支。顺序不能反更具体的带守卫的必须放前面。{ ... yield ... }分支里有多条语句时用花括号包起来最后yield交出返回值单表达式分支case WeChat w - ...直接写结果不用 yield。没有default为什么敢不写Payment 是 sealed三个 permitted 类型全覆盖 case null接住空值编译器认定穷尽了。类比 when银行卡分拣台上的二次扫码。先认出银行卡这个大类再扫一眼金额——超过 1000 的走大额人工审核通道其余走普通通道。类比 yield后厨出餐口。这个窗口里炒了好几个步骤算金额、拼文案最后一步把成品从出餐口递出来。再附一个经典等值 switch 的表达式化输入是 int不是 sealed 家族default 还得留着returnswitch(day){case1-周一写代码;case2-{Stringplan周二改 bug;yieldplan 写注释;// 多语句分支必须 yield}case3-周三看日志;default-休息日;// int 编译器不知道全部可能值default 不能省};箭头语法-天生不贯穿、不用 break——老冒号写法case 1: ... break;漏写 break 的贯穿事故从此绝迹。实测输出新写法输出和老写法逐行一致我本机JDK 21.0.12.1的真实输出 第 5 课模式匹配 switch --- 1) 老写法if-else instanceof 链 --- 微信支付wx_880159.9 元 支付宝ALI20240001120.0 元 银行卡普通支付6222****123450.0 元 银行卡大额支付6222****12342000.0 元需人工审核 支付方式不能是 null --- 2) 新写法模式匹配 switch输出应与老写法一一对应--- 微信支付wx_880159.9 元 支付宝ALI20240001120.0 元 银行卡普通支付6222****123450.0 元 银行卡大额支付6222****12342000.0 元需人工审核 支付方式不能是 null --- 3) 经典等值 switch箭头语法 yield --- 周一写代码 周二改 bug 写注释 周三看日志输出怎么读老写法、新写法各 5 行输出逐行一致微信走 WeChat 分支、支付宝走 Alipay、50 元银行卡走普通分支、2000 元银行卡被when守卫拦进大额分支、null 被case null接住——新写法没有改变业务行为只是写法升级这是重构最安全的证据。2000.0 元那行是{ ... yield ... }多语句分支产的先算yuan变量再 yield 拼文案。经典等值 switchday1单表达式分支直接出值day2多语句走了 yield全程没有 break。挑战题答案都在课程源码里⭐加支付方式给 Payment 家族加record Coupon(String code, long cents)记得更新 permits在 routeNew 里加case Coupon c - ...分支重新编译跑通。⭐改守卫门槛把银行卡大额门槛从 1000 元改成 500 元用 50 元、2000 元两个样例验证分支走向对不对。⭐⭐亲手玩穷尽性删掉 routeNew 的一个分支编译把报错再看一遍——编译器会报 “the switch expression does not cover all possible input values”然后改回来。⭐⭐老代码吃新语法把 routeOld 改成if (payment instanceof WeChat w)模式匹配变量写法——这是 Java 16 的 instanceof 模式匹配体会老代码也能先吃一口新语法。⭐⭐⭐挑战写一个feeOf(Payment p)方法switch 表达式微信收 0.6% 手续费、支付宝 0.8%、银行卡 1%大额 2000 元以上按 0.5%要求用 when 守卫处理银行卡分档打印四个样例的手续费。面试回答模板问switch 模式匹配解决了什么问题一句话结论它把 switch 从只能比等值升级成能按类型匹配并自动转型消灭了 instanceof 强转的样板代码。展开 1~2 句原理/例子case 后直接写类型加变量同时完成判断和转型when 守卫子句可以在类型内再按值细分配合 sealed 家族分支写全后编译器能做穷尽性检查漏分支编译就报错连 default 都不用写。收一句应用场景我现在写支付路由、消息处理器这种按类型分派的代码都用它路由表一眼看清比 if-else 链好维护得多。预判追问“什么时候不用写 default”——“输入是 sealed 封闭家族、分支覆盖全部 permitted 类型并接住 null时”“箭头和冒号能混用吗”——“不能一个 switch 里只能用一种”“多语句分支怎么返回值”——“花括号 yield”。总结表坑 → 原因 → 解法坑原因解法if-else instanceof 链越长越不敢动判断 强转 业务绞在一起模式匹配 switch一行完成判断转型绑定ClassCastException手动强转类型写错case 自动转型没有强转代码箭头和冒号混用编译报错两种语法不兼容一个 switch 只用-或只用:花括号分支忘了 yield多语句分支没有交值{ ... yield 值; }守卫和兜底顺序写反兜底先接住守卫永远走不到更具体的带 when 的分支放前面普通类型省 default 报错穷尽性只对 sealed 家族成立int/String 输入保留 defaultnull 输入 NPE没显式接 nullcase null -或靠 default关于这个系列本文属于Java 后端实战精通营系列Java 21 实战 10 课。完整代码在java21-journey 课程第 5 课lesson-05/src/main/java/com/java21/lesson05/含Payment.java密封支付家族 Main.java老写法/新写法对照gitclone https://gitee.com/j67mk2/java21-journey.gitcdjava21-journey/lesson-05 mvn-qcleaninstall-DskipTestsjava-cptarget/classes com.java21.lesson05.Main仓库地址是小写 j 的 j67mk2复制别丢字母。跑完会看到老写法、新写法各 5 行输出逐行一致。下一篇预告记录模式——case Order(String id, double amt)这种写法能在匹配的同时把 record 字段拆出来连o.id()都省了。掏心窝一句模式匹配 switch 是那种学了就回不去的特性。面试官让你写支付路由你掏出 switch 表达式 when 守卫再补一句配合 sealed 能穷尽、不用 default这一串下来就是加分项。跑出来的输出和我不一样评论区一起查。【发布信息】主标题switch 按类型匹配Java 21 一行干掉 if-else 强转链备选标题 2支付路由 if-else 越写越长Java 21 模式匹配 switch 让路由表一眼看清备选标题 3Java 21 模式匹配 switchwhen 守卫 穷尽性连 default 都不用写了标签建议java / Java21 / switch摘要建议支付路由的 if-else instanceof 链越写越长、强转还容易翻车。Java 21 模式匹配 switch 让 case 直接按类型匹配并自动转型when 守卫子句按值细分配合 sealed 家族实现穷尽性——分支写全连 default 都不用。附支付路由新旧写法对照、实测输出与面试回答模板。