Java 中 Function 与 apply 的实际应用场景分析(含优化前后案例)

 更新时间:2025年12月16日 09:48:48   作者:岁冉  
本文介绍了如何使用Java 8的Function函数式接口简化重复逻辑,包括判空、格式化、字段提取等常见场景,通过实际案例,展示了如何将多个字段的处理逻辑集中到一个函数中,从而提高代码的可读性和可维护性,感兴趣的朋友跟随小编一起看看吧

在日常开发中,我们会遇到一些代码重复度高、逻辑结构雷同的场景,比如:

  • 针对多个字段做相似的判空判断
  • 对多个字段的数值格式进行统一处理
  • 动态构造 VO 或 DTO 列表

以前这些逻辑通常依赖大量 if-else,导致代码冗长、可读性差。随着 Java 8 Lambda 的流行,我们可以借助 Function 函数式接口 让代码更简洁、更易维护。

本文通过一个实际场景,讲解:

  • Function 是什么
  • apply 方法的作用
  • 在实际业务里如何利用 Function 简化重复逻辑
  • 更多 Function 的高级用法

🧩 一、Function 是什么?

Java 8 提供了大量函数式接口(位于 java.util.function 包里),其中 Function<T, R> 是最常用的一个:

简单理解:

Function 表示一个“输入一个参数(T),输出一个结果(R)”的函数。

例如:

  • 输入是 String,输出是 Integer
  • 输入是一个实体对象,输出是某个字段的值
  • 输入是一个可能为 null 的字段,输出是安全值

🧲 二、apply 做什么?

apply() 是 Function 的核心方法,用来执行函数逻辑,你可以把 apply() 理解成“执行这个函数”。比如如下方法,我们需要获取每个字符串的字符串长度:

Function<String, Integer> lengthFunc = str -> str.length();
int len = lengthFunc.apply("hello");  // 返回 5

📘 三、业务场景:字段多、判空多、逻辑重复

💡1、传统做法

假设我们有一个实体(例如某企业的年度指标数据):

class IndicatorEntity {
    private String amountA;
    private String amountB;
    private String amountC;
    // ...getter/setter
}

我们需要根据它生成一个 VO 列表,输出时存在各种问题,比如

  • 字段可能为 null
  • 字段可能为空字符串
  • 需要统一格式化为两位小数
  • 需要填充默认值 “0”……

传统写法会有大量的 if-else 判断,大量重复(下述代码中 format() 表示规范字段的值,如实现判空、保留两位小数等逻辑):

List<ItemVO> list = new ArrayList<>();
if (StringUtils.isNotBlank(entity.getAmountA())) {
    list.add(new ItemVO("指标A", format(entity.getAmountA()), "吨"));
} else {
    list.add(new ItemVO("指标A", "0", "吨"));
}
if (StringUtils.isNotBlank(entity.getAmountB())) {
    list.add(new ItemVO("指标B", format(entity.getAmountB()), "吨"));
} else {
    list.add(new ItemVO("指标B", "0", "吨"));
}
// ...重复更多

💡2、使用 Function 优化:统一 null 处理与格式化

我们使用一个 Function<String, String>,用于将字段安全地转换成非空:

Function<String, String> safeFormat = val -> val == null ? "" : val;

之后构造字段数组如下:

Object[][] fields = {
    {"指标A", safeFormat.apply(entity.getAmountA()), "吨"},
    {"指标B", safeFormat.apply(entity.getAmountB()), "吨"},
    {"指标C", safeFormat.apply(entity.getAmountC()), "吨"},
    // 其他指标依次添加
};

之后对其统一格式化处理:

List<ItemVO> result = new ArrayList<>();
for (Object[] field : fields) {
    String name = (String) field[0];
    String rawValue = (String) field[1];
    String unit = (String) field[2];
    String formattedValue = "0";
    if (StringUtils.isNotBlank(rawValue)) {
        try {
            // 统一格式化,例如 NumberUtil.formatStr(),或其他你需要对字符串进行的操作
            formattedValue = format(rawValue);   
        } catch (Exception ignored) {
            // 你需要进行的异常操作
        }
    }
    result.add(new ItemVO(name, formattedValue, unit));
}

经过优化后:

  • 重复逻辑消失
  • 判空与格式化集中处理
  • 字段配置化,易维护
  • 添加新字段只需改一个数组,便于之后添加字段到处添加 if-else,修改方便。

🎯 四、Function 的实际适用场景总结

① null 安全处理(最常见)

② 字段提取器(Getter 复用)——比如多字段统一处理,适用于:动态抽取实体字段值、在工具类中避免大量重复 getter 调用:

<T, R> R getValue(T entity, Function<T, R> getter) {
    return getter.apply(entity);
}
String value = getValue(entity, IndicatorEntity::getAmountA);

③ 通用格式化处理——例如统一格式化数字、日期:

Function<String, String> formatAmount = s -> {
    if (StringUtils.isBlank(s)) return "0";
    return NumberUtil.formatStr(s, 2);
};

④ 配置化字段处理

如本文案例,将字段名称、原始值、单位放在数组或列表中,之后统一判空、格式化、填充默认值、构造VO。

🧨 五、进一步延申:组合函数 compose 与 andThen

compose:先执行参数里的 Function,再执行当前 Function

Function<String, Integer> length = s -> s.length();
Function<String, String> trim = s -> s.trim();
int len = length.compose(trim).apply("  hi  "); // 2

andThen:先执行当前 Function,再执行参数里的 Function

int len = trim.andThen(length).apply("  hi  "); // 2

适用于多步骤处理,例如:

  • 先判空 → 再格式化
  • 先 trim → 再校验

到此这篇关于Java 中 Function 与 apply 的实际应用场景分析(含优化前后案例)的文章就介绍到这了,更多相关java function 与 apply用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis plus多租户方案的实战踩坑记录

    Mybatis plus多租户方案的实战踩坑记录

    MybaitsPlus多租户处理器是一个对于多租户问题的解决方案,下面这篇文章主要给大家介绍了关于Mybatis plus多租户方案踩坑的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-12-12
  • Java线程中断及线程中断的几种使用场景小结

    Java线程中断及线程中断的几种使用场景小结

    在并发编程中,合理使用线程中断机制可以提高程序的鲁棒性和可维护性,本文主要介绍了Java线程中断及线程中断的几种使用场景小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Java中实现Map按值排序的多种方法

    Java中实现Map按值排序的多种方法

    Java的Map接口默认不保证元素的顺序,本文介绍如何使用TreeMap、Collections.sort()结合Entry、Stream API以及Guava库等技术手段实现Map按值排序,每种方法都有其特点,在选择具体方法时应考虑项目的具体需求及个人偏好,需要的朋友可以参考下
    2025-03-03
  • 解决线程并发redisson使用遇到的坑

    解决线程并发redisson使用遇到的坑

    这篇文章主要介绍了解决线程并发redisson使用遇到的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • 使用Java接收和处理OpenTelemetry数据的完整指南

    使用Java接收和处理OpenTelemetry数据的完整指南

    在现代分布式系统中,OpenTelemetry 成为了一种常见的标准,用于跟踪和监控应用程序的性能和行为,OTLP是 OpenTelemetry 社区定义的一种数据传输协议,文将介绍如何使用 Java 编写代码来接收和处理 OTLP 数据,需要的朋友可以参考下
    2024-04-04
  • SpringBoot加载多个配置文件实现dev、product多环境切换的方法

    SpringBoot加载多个配置文件实现dev、product多环境切换的方法

    这篇文章主要介绍了SpringBoot加载多个配置文件实现dev、product多环境切换,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • Java中synchronized用法汇总

    Java中synchronized用法汇总

    使用 synchronized 无需手动执行加锁和释放锁的操作,我们只需要声明 synchronized 关键字就可以了,JVM 层面会帮我们自动的进行加锁和释放锁的操作,我们今天重点来看一下synchronized 的几种用法
    2022-04-04
  • 总结Java中线程的状态及多线程的实现方式

    总结Java中线程的状态及多线程的实现方式

    Java中可以通过Thread类和Runnable接口来创建多个线程,线程拥有五种状态,下面我们就来简单总结Java中线程的状态及多线程的实现方式:
    2016-07-07
  • SpringBoot中的Lombok库及使用举例详解

    SpringBoot中的Lombok库及使用举例详解

    Lombok是一个Java库,通过注解的方式简化代码编写,减少样板代码,它能够自动生成getter、setter、构造函数、toString等方法,提升开发效率,这篇文章主要介绍了SpringBoot中的Lombok库,需要的朋友可以参考下
    2025-05-05
  • 使用Springboot根据配置文件动态注入接口实现类

    使用Springboot根据配置文件动态注入接口实现类

    这篇文章主要介绍了使用Springboot根据配置文件动态注入接口实现类,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论