尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

告别“if-else地狱“!Java 21模式匹配,代码优雅了10倍

告别“if-else地狱“!Java 21模式匹配,代码优雅了10倍
📅 发布时间:2026/6/30 11:13:51

告别"if-else地狱"!Java 21模式匹配,代码优雅了10倍

如果你打开一个方法,看到的是50行if-else嵌套,你会是什么感受?反正我是想砸键盘。

大家好,我是卷毛。

前段时间接手了一个老项目,有个订单处理方法,if-else嵌套了7层,478行代码。我花了3天重构完,用的是什么?Java 21的模式匹配。

今天这篇文章,我把自己实际用到的5种重构手法分享出来,每种都有真实代码对比,保证你看完就能用。


先看个"恐怖故事"

这是真实代码,我只改了变量名:

// 重构前 —— 478行的怪物publicvoidprocessOrder(Orderorder){if(order!=null){if(order.getType()==OrderType.NORMAL){if(order.getStatus()==OrderStatus.PENDING){if(order.getAmount()>1000){if(order.getUser().getLevel()==UserLevel.VIP){// VIP大额待处理订单if(order.getPaymentMethod()==PaymentMethod.WECHAT){vipWechatLargeOrderProcess(order);}elseif(order.getPaymentMethod()==PaymentMethod.ALIPAY){vipAlipayLargeOrderProcess(order);}else{vipOtherLargeOrderProcess(order);}}else{// 普通用户大额待处理订单normalLargeOrderProcess(order);}}else{// 小额订单处理...// 还有3层嵌套...}}elseif(order.getStatus()==OrderStatus.PAID){// 已支付订单处理...}elseif(order.getStatus()==OrderStatus.CANCELLED){// 取消订单处理...}}elseif(order.getType()==OrderType.GROUP){// 团购订单...// 又是几层嵌套...}}}

看完是不是血压上来了?别急,我们一步步来。


手法一:instanceof模式匹配 —— 干掉强转

痛点:instanceof判断完还要强转,啰嗦。

// ❌ 以前if(objinstanceofString){Stringstr=(String)obj;// 多余的强转System.out.println(str.length());}// ✅ Java 21if(objinstanceofStringstr){System.out.println(str.length());}

实战场景:

// 处理不同类型的消息体publicvoidhandleMessage(Objectmessage){if(messageinstanceofTextMessagetm){textProcessor.process(tm.getContent());}elseif(messageinstanceofImageMessageim){imageProcessor.process(im.getUrl(),im.getWidth(),im.getHeight());}elseif(messageinstanceofVideoMessagevm){videoProcessor.process(vm.getUrl(),vm.getDuration());}elseif(messageinstanceofnull){log.warn("收到空消息");}}

一行代码省掉了声明+强转,10个分支就省10行。


手法二:switch模式匹配 —— 替代if-else链

痛点:基于类型的分支判断,if-else写起来又长又丑。

// ❌ 以前 —— 类型判断+强转,又臭又长publicdoublecalculateArea(Shapeshape){if(shapeinstanceofCircle){Circlec=(Circle)shape;returnMath.PI*c.getRadius()*c.getRadius();}elseif(shapeinstanceofRectangle){Rectangler=(Rectangle)shape;returnr.getWidth()*r.getHeight();}elseif(shapeinstanceofTriangle){Trianglet=(Triangle)shape;doubles=(t.getA()+t.getB()+t.getC())/2;returnMath.sqrt(s*(s-t.getA())*(s-t.getB())*(s-t.getC()));}else{thrownewIllegalArgumentException("未知形状: "+shape.getClass().getName());}}// ✅ Java 21 —— switch模式匹配publicdoublecalculateArea(Shapeshape){returnswitch(shape){caseCirclec->Math.PI*c.radius()*c.radius();caseRectangler->r.width()*r.height();caseTrianglet->{doubles=(t.a()+t.b()+t.c())/2;yieldMath.sqrt(s*(s-t.a())*(s-t.b())*(s-t.c()));}casenull->thrownewIllegalArgumentException("形状不能为null");default->thrownewIllegalArgumentException("未知形状");};}

注意:switch模式匹配要求穷举所有可能,如果你用了sealed class,编译器会帮你检查。


手法三:Record + 模式匹配 —— 替代DTO地狱

痛点:处理不同类型的消息/事件,DTO类一堆,处理逻辑if-else一堆。

先定义sealed接口和Record:

// 定义一个密封接口,限定实现类型publicsealedinterfacePaymentEventpermitsPaymentSuccess,PaymentFailed,RefundProcessed{}publicrecordPaymentSuccess(StringorderId,BigDecimalamount,StringtradeNo)implementsPaymentEvent{}publicrecordPaymentFailed(StringorderId,Stringreason,intretryCount)implementsPaymentEvent{}publicrecordRefundProcessed(StringorderId,BigDecimalrefundAmount,StringrefundNo)implementsPaymentEvent{}

处理逻辑:

// 简洁、类型安全、编译器保证穷举publicvoidhandlePaymentEvent(PaymentEventevent){switch(event){casePaymentSuccess(StringorderId,BigDecimalamount,StringtradeNo)->orderService.confirmPayment(orderId,amount,tradeNo);casePaymentFailed(StringorderId,Stringreason,intretryCount)when retryCount<3->retryService.scheduleRetry(orderId,retryCount+1);casePaymentFailed(StringorderId,Stringreason,intretryCount)->notifyService.notifyFailure(orderId,reason);caseRefundProcessed(StringorderId,BigDecimalrefundAmount,StringrefundNo)->refundService.completeRefund(orderId,refundAmount,refundNo);}}

注意看when retryCount < 3这个guard条件——以前要用if嵌套实现的逻辑,现在一行搞定。

Record解构的模式匹配对比

// Record组件可以直接解构casePaymentSuccess(StringorderId,BigDecimalamount,StringtradeNo)// 也可以只绑定部分组件,用 _ 忽略不关心的casePaymentSuccess(StringorderId,_,_)// 甚至全忽略casePaymentSuccess(_,_,_)

手法四:null安全模式匹配 —— 告别NPE恐惧

痛点:null检查散落各处,漏了一个就NPE。

// ❌ 以前 —— 各种null检查publicStringgetUserName(Useruser){if(user==null){return"匿名用户";}if(user.getProfile()==null){returnuser.getName();}if(user.getProfile().getNickname()==null){returnuser.getName();}returnuser.getProfile().getNickname();}// ✅ Java 21 —— null模式匹配publicStringgetUserName(Useruser){returnswitch(user){casenull->"匿名用户";caseUseru when u.profile()==null->u.name();caseUseru when u.profile().nickname()==null->u.name();caseUseru->u.profile().nickname();};}

配合Optional更优雅:

publicStringgetUserName(Useruser){returnOptional.ofNullable(user).map(User::getProfile).map(Profile::getNickname).orElseGet(()->Optional.ofNullable(user).map(User::getName).orElse("匿名用户"));}

手法五:重构开头的"恐怖故事"

用上面4种手法组合,478行变62行:

// 重构后 —— 62行,清晰可维护publicvoidprocessOrder(Orderorder){switch(order){casenull->log.warn("收到空订单");caseOrdero when o.type()==OrderType.NORMAL->processNormalOrder(o);caseOrdero when o.type()==OrderType.GROUP->processGroupOrder(o);}}privatevoidprocessNormalOrder(Orderorder){switch(order){caseOrder(varid,_,varamount,varstatus,varuser,varpayment)when status==OrderStatus.PENDING&&amount.compareTo(BigDecimal.valueOf(1000))>0&&user.level()==UserLevel.VIP->processVipLargeOrder(order,payment);caseOrder(_,_,varamount,varstatus,varuser,_)when status==OrderStatus.PENDING&&amount.compareTo(BigDecimal.valueOf(1000))>0->normalLargeOrderProcess(order);caseOrder(_,_,_,varstatus,_,_)when status==OrderStatus.PAID->paidOrderProcess(order);caseOrder(_,_,_,varstatus,_,_)when status==OrderStatus.CANCELLED->cancelledOrderProcess(order);default->pendingSmallOrderProcess(order);}}privatevoidprocessVipLargeOrder(Orderorder,PaymentMethodpayment){switch(payment){caseWECHAT->vipWechatLargeOrderProcess(order);caseALIPAY->vipAlipayLargeOrderProcess(order);default->vipOtherLargeOrderProcess(order);}}

478行 → 62行,而且每一行都在说"做什么",而不是"怎么判断"。


重构前后对比

维度重构前重构后
代码行数478行62行
最大嵌套层级7层2层
圈复杂度348
新增分支成本在大方法里加if-else加一个case
可测试性差,一个方法测所有分支好,每个子方法独立测试
可读性需要跟踪嵌套逻辑顺序阅读,一目了然

实操建议

  1. 先加测试再重构:模式匹配改变的是代码结构,不是逻辑,测试是安全网
  2. 优先用sealed class:编译器帮你检查穷举,少一个case直接编译报错
  3. guard条件别写太复杂:when后面超过2个条件就考虑提取方法
  4. Record优先:新代码用Record替代传统的DTO/VO,配合模式匹配效果最好
  5. 不要为了用而用:简单的if-else没必要硬改成switch,工具是解决问题的不是炫技的

写在最后

模式匹配不是什么"新潮语法糖",它是Java在向函数式编程范式靠拢的重要一步。用了之后你会发现,代码不只是变短了,而是变清晰了——你在表达"做什么",而不是"怎么做"。

9年Java开发,我越来越觉得:好代码不是写得巧妙,而是写得让人一看就懂。


📌我是卷毛,9年Java开发,专注Java技术实战分享。

这篇文章如果对你有帮助,点个「在看」和「关注」,是我持续输出的最大动力。

下一篇我们聊虚拟线程的实战踩坑经验,关注不迷路!

《卷毛的技术笔记》—— 一起卷出技术力。🔥

相关新闻

  • 华为OD机试2025C卷-IPv4地址转换成整数[100分](Java_Python3_C++_C语言_JsNode_Go)实现100%通过率
  • 从零搭建ROS-Gazebo仿真环境:以Husky机器人为例实践多SLAM算法评估
  • 公证需要去哪里办理?常见公证事项要准备哪些材料?

最新新闻

  • 2026深度实测:7款主流AI编程工具选型全指南
  • 终极离线思维导图解决方案:DesktopNaotu桌面版脑图完整指南
  • 收藏!小白程序员必看:从模型层进阶系统层,轻松拿下大模型面试 实战!
  • 硬件盲盒任务其实挺简单的
  • Synopsys DC实战:从零构建高效综合SDC约束的完整指南
  • Selenium自动化测试实战:从元素定位到反爬策略的进阶技巧

日新闻

  • 【计算机毕业设计案例】基于 Spring Boot+Vue 的电影售票系统设计与实现 前后端分离架构下影院在线购票管理平台(程序+文档+讲解+定制)
  • 到底 TMD 用哪个: npm, pnpm, Yarn, Bun, Deno? 傻瓜, 当然用 npm 啦
  • Google限制Meta使用Gemini模型 凸显AI授权竞争白热化

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号