首页 > 其他分享 >利用 Function 接口告别冗余(屎山)代码

利用 Function 接口告别冗余(屎山)代码

时间:2024-12-02 14:56:46浏览次数:9  
标签:Function void 接口 public user new null ID 冗余

前言
在 Java 开发的征途中,我们时常与重复代码不期而遇。这些重复代码不仅让项目显得笨重,更增加了维护成本。幸运的是,Java 8 带来了函数式编程的春风,以 Function 接口为代表的一系列新特性,为我们提供了破除这一难题的利剑。本文将以一个实际应用场景为例,即使用 Java 8 的函数式编程特性来重构数据有效性断言逻辑,展示如何通过 SFunction(基于 Java 8 的 Lambda 表达式封装)减少代码重复,从而提升代码的优雅性和可维护性。
背景故事
数据校验的烦恼想象一下,在一个复杂的业务系统中,我们可能需要频繁地验证数据库中某个字段值是否有效,是否符合预期值。传统的做法可能充斥着大量相似的查询逻辑,每次都需要手动构建查询条件、执行查询并处理结果,这样的代码既冗长又难以维护。例如以下两个验证用户 ID 和部门 ID 是否有效的方法,虽然简单,但每次需要校验不同实体或不同条件时,就需要复制粘贴并做相应修改,导致代码库中充满了大量雷同的校验逻辑,给维护带来了困扰。

// 判断用户 ID 是否有效
public void checkUserExistence(String userId) {
    User user = userDao.findById(userId);
    if (user == null) {
        throw new RuntimeException("用户ID无效");
    }
}

// 判断部门 ID 是否有效
public void checkDeptExistence(String deptId) {
    Dept dept = deptDao.findById(deptId);
    if (dept == null) {
        throw new RuntimeException("部门ID无效");
    }   
}

Java 8 的魔法棒
函数式接口Java 8 引入了函数式接口的概念,其中 Function<T, R> 是最基础的代表,它接受一个类型 T 的输入,返回类型 R 的结果。而在 MyBatis Plus 等框架中常用的 SFunction 是对 Lambda 表达式的进一步封装,使得我们可以更加灵活地操作实体类的属性。
实战演练
重构断言方法下面的 ensureColumnValueValid 方法正是利用了函数式接口的魅力,实现了对任意实体类指定列值的有效性断言:

/**
 * 确认数据库字段值有效(通用)
 * 
 * @param <V> 待验证值的类型
 * @param valueToCheck 待验证的值
 * @param columnExtractor 实体类属性提取函数
 * @param queryExecutor 单条数据查询执行器
 * @param errorMessage 异常提示信息模板
 */
public static <T, R, V> void ensureColumnValueValid(V valueToCheck, SFunction<T, R> columnExtractor, SFunction<LambdaQueryWrapper<T>, T> queryExecutor, String errorMessage) {
    if (valueToCheck == null) return;
    
    LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
    wrapper.select(columnExtractor);
    wrapper.eq(columnExtractor, valueToCheck);
    wrapper.last("LIMIT 1");

    T entity = queryExecutor.apply(wrapper);
    R columnValue = columnExtractor.apply(entity);
    if (entity == null || columnValue == null)
        throw new DataValidationException(String.format(errorMessage, valueToCheck));
}

改造后使用如下代码所示:

 

public void assignTaskToUser(AddOrderDTO dto) {
    ensureColumnValueValid(dto.getUserId(), User::getId, userDao::getOne, "用户ID无效");
    ensureColumnValueValid(dto.getDeptId(), Dept::getId, deptDao::getOne, "部门ID无效");    
    ensureColumnValueValid(dto.getCustomerId(), Customer::getId, customerDao::getOne, "客户ID无效");
    ensureColumnValueValid(dto.getDeptId(), Dept::getId, deptDao::getOne, "部门ID无效");
    ensureColumnValueValid(dto.getSupplieId(), Supplie::getId, supplierDao::getOne, "供应商ID无效");

    // 现在可以确信客户存在
    Customer cus = customerDao.findById(dto.getCustomerId());     
    
    // 创建订单的逻辑...
}

再如下例子:

  // 优化前  
public void validateUser(User user) { if (user.getName() == null || user.getName().isEmpty()) { throw new IllegalArgumentException("Name cannot be empty"); } if (user.getAge() < 18) { throw new IllegalArgumentException("Age must be at least 18"); } if (user.getEmail() == null || !user.getEmail().matches("regex")) { throw new IllegalArgumentException("Invalid email address"); } } // 优化后 public static <T> void validate(T obj, Function<T, Boolean> validator, String errorMessage) { if (!validator.apply(obj)) { throw new IllegalArgumentException(errorMessage); } } public static void validateUser2(User user) { validate(user, u -> u.getName() != null && !u.getName().isEmpty(), "Name cannot be empty"); validate(user, u -> u.getAge() >= 18, "Age must be at least 18"); validate(user, u -> u.getEmail() != null && u.getEmail().matches("regex"), "Invalid email address"); }

 

参考博客:利用 Function 接口告别冗余(屎山)代码

 

标签:Function,void,接口,public,user,new,null,ID,冗余
From: https://www.cnblogs.com/jelly12345/p/18581873

相关文章

  • 使用Function与BiConsumer动态获取与操作对象中的属性
    代码:packagecom.xxx.xxx.utils;importcom.alibaba.fastjson.JSON;importlombok.Data;importjava.util.function.BiConsumer;importjava.util.function.Function;/***函数测试*/publicclassTest{@DatapublicstaticclassTestObj{pri......
  • 携程酒店库存查询接口(接单被骗直接放出接口)
    本来是接单的,做了一个查询库存自动到他们系统里下库存的单子,做好部署好,老板可能也有点技术,拿了跑路了,那就放出来,给大家用接口请求格式:https://down.ychengsnsm.com/jd/api.php?id=48565681&checkinDate=2024-12-30测试图:id就是酒店id,随便到携程到个酒店,如图,圈起来的就是id,chec......
  • 身份证OCR识别API接口的功能特点以及优势分析
    如今,智能终端和各种APP中具备移动OCR文字识别、身份证识别等功能已经成为当下社会发展的必备。对于各类APP来说,只要将身份证OCR识别数据接口集成到APP中,即可通过手机摄像头扫描识别身份证信息。至于识别的准确性和速度,则取决于所选择的数据接口平台。本文将从身份证OCR识......
  • D85【python 接口自动化学习】- pytest基础用法
    day85pytest指定目录或文件执行测试用例学习日期:20241201学习目标:pytest基础用法--pytest指定目录,文件执行测试用例学习笔记:pytest指定目录或文件执行测试用例终端执行用例pytest不跟目标目录或文件,执行根目录下所有符合规则的测试用例终端执行用例pytest指定......
  • C#面向对象之抽象,接口,运算符重载,属性,索引器
    目录1抽象1.1抽象方法1.1.1抽象方法1.1.2虚方法1.1.3new1.2抽象属性1.3抽象示例2接口2.1定义2.2简单使用2.2.1声明使用接口2.2.2接口继承2.3接口显式实现和隐式实现2.3.1隐式实现2.3.2显式实现2.3.3多接口实现中的应用3运算符重载operator3.1简介3.2示例4属......
  • 通过实现 FactoryBean 接口注入 Bean
    原文:如何使用Spring的FactoryBean接口在Spring容器中有两类的Bean,一类是普通的Bean,一类是工厂Bean。这两种Bean都是被Spring的容器进行管理的。而Spring也提供了一个接口用于扩展工厂Bean,我们只要实现org.springframework.beans.factory.FactoryBean即可。使......
  • 开源低代码平台-Microi吾码-接口引擎实战:微信v3支付JSAPI下单
    Microi吾码-接口引擎实战:微信v3支付JSAPI下单简介预览图业务逻辑接口引擎代码Microi吾码-系列文档接口引擎实战-系列文档简介接口引擎与第三方平台对接无所不能,下一篇介绍对接微信支付回调(含签名验证)预览图业务逻辑参考微信支付官方文档:https://pay.weixin.qq......
  • 申请量化API接口的步骤有哪些?
    炒股自动化:申请官方API接口,散户也可以python炒股自动化(0),申请券商API接口python炒股自动化(1),量化交易接口区别Python炒股自动化(2):获取股票实时数据和历史数据Python炒股自动化(3):分析取回的实时数据和历史数据Python炒股自动化(4):通过接口向交易所发送订单Python炒股自动化(5):......
  • Java小白学习之---接口
    1.什么是接口?接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来2.接口语法interface接口名{//属性//方法(1.抽象方法2默认实现方法3.静态方法)}class类名implements接口{自己属性;自己方法;必须实现的接口的抽象......
  • 必看版指南:BTB扩展接口——LCD、Camera、UART、I2C…
    本次我将把BTB扩展接口——LCD、Camera、UART、I2C等作为介绍,特别分享Air201硬件BTB扩展接口相关内容。其板载BTB24PIN连接器,可用于扩展连接LCD、Camera、Uart、I2C等外设。通过BTB连接器,可以扩展使用PWRKEY引脚控制开关机,一路UART1串口接口连接外设,4路模拟IO口,2路带唤醒功能的......