当前位置: 首页 > news >正文

分享些 Function 和 枚举的经典使用案例

在这里插入图片描述

在 Java 项目里,枚举常被用来表示状态、类型或操作。但大多数团队对枚举的使用停留在“写常量、带点属性”的阶段,比如:

public enum BizType {ORDER, INVOICE, PAYMENT
}

这种枚举就是个“标签”,本身不具备行为。要根据枚举执行不同逻辑时,往往写成一堆 switch-caseif-else

而我后来在实践中发现:把 Function 绑定到 枚举 上,可以让逻辑和数据天然耦合,形成一种轻量的“枚举策略模式”。


1. 代替 switch-case 的支付示例

最典型的场景是支付业务。以前我们是这样写的:

if (payType == ALIPAY) {return doAliPay(request);
} else if (payType == WECHAT) {return doWechatPay(request);
} else if (payType == BANK) {return doBankPay(request);
}

重构后,用枚举直接绑定处理函数:

public enum PayType {ALIPAY(req -> PayService.aliPay(req)),WECHAT(req -> PayService.wechatPay(req)),BANK(req -> PayService.bankPay(req));private final Function<PayRequest, PayResult> function;PayType(Function<PayRequest, PayResult> function) {this.function = function;}public PayResult process(PayRequest req) {return function.apply(req);}
}

调用时只需:

PayResult result = payType.process(request);

好处:

  • 新增支付方式时,只改枚举本身,不用动 switch-case
  • 枚举项 自带行为,和“数据”天然绑定。
  • 枚举 + Function 的写法,比传统策略模式少了冗余类文件。

2. 枚举做“状态机”的小技巧

在一个开票系统里,我们有多个发票状态:INITSUBMITTEDSUCCESSFAILED。不同状态下,系统要执行不同的动作。

传统写法是一个大 switch

switch (status) {case INIT: doInit(); break;case SUBMITTED: doSubmitted(); break;case SUCCESS: doSuccess(); break;case FAILED: doFailed(); break;
}

重构后:

public enum InvoiceStatus {INIT(ctx -> InvoiceHandler.init(ctx)),SUBMITTED(ctx -> InvoiceHandler.submitted(ctx)),SUCCESS(ctx -> InvoiceHandler.success(ctx)),FAILED(ctx -> InvoiceHandler.failed(ctx));private final Function<InvoiceContext, Void> function;InvoiceStatus(Function<InvoiceContext, Void> function) {this.function = function;}public void handle(InvoiceContext ctx) {function.apply(ctx);}
}

调用:

invoiceStatus.handle(context);

这里枚举天然就是“状态机的节点”,Function 直接绑定行为,让代码逻辑自解释。


3. 枚举做计算器:更贴近业务的表达

在财务模块里,我们需要根据不同的运算符执行计算,比如:

if ("ADD".equals(op)) {return a.add(b);
} else if ("SUB".equals(op)) {return a.subtract(b);
} else if ("MUL".equals(op)) {return a.multiply(b);
}

枚举 + Function 的写法:

public enum Operator {ADD((a, b) -> a.add(b)),SUB((a, b) -> a.subtract(b)),MUL((a, b) -> a.multiply(b)),DIV((a, b) -> a.divide(b, RoundingMode.HALF_UP));private final BiFunction<BigDecimal, BigDecimal, BigDecimal> op;Operator(BiFunction<BigDecimal, BigDecimal, BigDecimal> op) {this.op = op;}public BigDecimal apply(BigDecimal a, BigDecimal b) {return op.apply(a, b);}
}

调用:

BigDecimal result = Operator.MUL.apply(new BigDecimal("12"), new BigDecimal("8"));

业务代码可读性直接提升:Operator.MUL.apply(12, 8),一眼就能看懂“乘法操作”。


4. 我的实践体会

  • 适用场景:当枚举不仅表示“值”,还天然带有“处理逻辑”时,用 Function 封装行为非常自然。
  • 比策略模式更轻:很多团队一上来就用策略模式,类会暴增;而枚举 + Function 足够轻巧,维护成本低。
  • 注意职责边界:别把一堆复杂逻辑硬塞到枚举里,否则枚举变成“大怪物”。我的经验是:枚举负责路由,复杂逻辑交给外部 Service
  • 调试友好:当业务报错时,可以直接打印枚举名,日志天然带有“当前逻辑标签”,比硬编码的 if-else 更清晰。

结语

Function 和枚举的结合,是我在 Java 开发里最喜欢的一个“小技巧”。它既保留了枚举的 强约束性,又引入了函数式的 灵活性

和传统的策略模式相比,它更轻、更直观,写出来的代码逻辑自带文档属性。很多时候,只要看到枚举定义,你就能立即知道系统有哪些行为,以及每个行为的处理方式。

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 什么是 Cookie?简单介绍与使用方法

  • 什么是 Session?如何应用?

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • 如何理解应用 Java 多线程与并发编程?

  • 把握Java泛型的艺术:协变、逆变与不可变性一网打尽

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 如何理解线程安全这个概念?

  • 理解 Java 桥接方法

  • Spring 整合嵌入式 Tomcat 容器

  • Tomcat 如何加载 SpringMVC 组件

  • “在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”

  • “避免序列化灾难:掌握实现 Serializable 的真相!(二)”

  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

  • 解密 Redis:如何通过 IO 多路复用征服高并发挑战!

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”

  • Java 中消除 If-else 技巧总结

  • 线程池的核心参数配置(仅供参考)

  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)

  • Java 枚举的几个常用技巧,你可以试着用用

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)

  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)

http://www.dtcms.com/a/349273.html

相关文章:

  • 【RAGFlow代码详解-1】概述
  • 青少年软件编程(python六级)等级考试试卷-客观题(2023年3月)
  • 同步阻塞和异步非阻塞是什么?
  • Web开发中的CGI:通用网关接口详解
  • 软件测试用例指南:覆盖 6 大设计方法
  • 二、GP/GS流程图
  • Spring面试题及详细答案 125道(16-25) -- 核心概念与基础2
  • 工程师的自我修养
  • Linux --网络基础概念
  • 08-系统能力调用与权限管理
  • Python爬虫-解决在抓包的过程中,找不到接口地址的问题
  • ViLU: Learning Vision-Language Uncertainties for Failure Prediction
  • C++ 容器——vector
  • PyTorch入门实战:MNIST数据集加载与可视化详解
  • 一、基因组选择(GS)与基因组预测(GP)
  • 【K8s】整体认识K8s之namespace
  • OpenIM应用机器人自动应答
  • 基于陌讯视觉算法的扶梯大件行李识别技术实战:误检率↓79%的工业级解决方案
  • 大模型中的意图识别
  • DMA-API(alloc和free)调用流程分析(十)
  • 胸部X光片数据集:健康及肺炎2类,14k+图像
  • 【网络运维】Shell脚本编程:函数
  • 大件垃圾识别精准度↑90%!陌讯多尺度融合模型在智慧环卫的落地实践
  • 鸿蒙ArkTS 基础篇-03-对象
  • 【黑色星期五输出当年有几个】2022-10-23
  • 单词搜索+回溯法
  • Windows客户端部署和管理
  • Week 13: 深度学习补遗:RNN的训练
  • 青少年软件编程(python五级)等级考试试卷-客观题(2023年12月)
  • 2024年09月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试