jdk8之Function<T,R>场景应用

本文介绍如何使用Java 8的Function<T,R>接口来重构重复代码,通过封装通用函数减少代码冗余,遵循DRY原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

日常编程中,如果使用Idea时总会遇到破浪线的代码块,鼠标悬浮上去,提示Found Duplicated Code in XXX。从代码设计的角度来讲,不符合DRY(Don't Repeat Yourself)原则。那我们又如何改善你眼前看到的一切呢?对于大多数同学来讲,肯定视而不见;但对于那么一丢丢同学来讲,却无法接受这样的代码,总想重构一下。

1.场景再现

/**
     * 分页查出当前资金方绑定产品列表
     * @param form
     * @return
     */
    @LogMonitor("资金方管理")
    public Result<PageVO<ProductVo>> loadBindRecords(PageForm<FundProductForm> form) {
        List<ProductVo> productVos = Collections.emptyList();
        int count = 0;
        try {
            List<Product> products = fundProductService.selectBindProductByParams(form);
            if (CollectionUtils.isEmpty(products)) {
                return Result.failInEmptyRecord(null);
            }
            Map<String, String> productTypeMap = diamondConfigProxy.queryProductType().stream().collect(Collectors.toMap(ProductTypeRe::getCode, ProductTypeRe::getName));
            productVos = new ProductVoConvertor().convertList(products, productTypeMap);
            count = fundProductService.getBindProductCount(form);
        }catch (Exception e){
            LOGGER.error("{}loadBindRecords加载数据异常,form={}",LOG_TITLE, JSON.toJSON(form),e);
            return  Result.fail(PageVO.newInstance(count,productVos));
        }
        return Result.suc(PageVO.newInstance(count,productVos));
    }

    /**
     * 分页查出当前资金方尚未绑定产品列表
     * @param form
     * @return
     */
    @LogMonitor("资金方管理")
    public Result<PageVO<ProductVo>> loadNotBindRecords(PageForm<FundProductForm> form) {
        List<ProductVo> productVos = Collections.emptyList();
        int count = 0;
        try {
            List<Product> products = fundProductService.selectNotBindProductByParams(form);
            if (CollectionUtils.isEmpty(products)) {
                return Result.failInEmptyRecord(null);
            }
            Map<String, String> productTypeMap = diamondConfigProxy.queryProductType().stream().collect(Collectors.toMap(ProductTypeRe::getCode, ProductTypeRe::getName));
            productVos = new ProductVoConvertor().convertList(products, productTypeMap);
            count = fundProductService.getNotBindProductCount(form);
        }catch (Exception e){
            LOGGER.error("{}loadNotBindRecords加载数据异常,form={}",LOG_TITLE, JSON.toJSON(form),e);
            return  Result.fail(PageVO.newInstance(count,productVos));
        }
        return Result.suc(PageVO.newInstance(count,productVos));
    }

上面就是个方法,发现方法体中大部分代码几乎一样的,鼠标悬浮上去提示如下:
在这里插入图片描述
我们分析上述两个方法,得知什么结论呢?

  • 1、方法入参一致。
  • 2、方法返回参数一致。
  • 3、方法体处理逻辑几乎一致,唯一区别就是调用 fundProductService.selectXXX 这句代码。

2.Function<T,R>

该函数是jdk8新出来的,用于实现函数式编程。如果它没有出现,传统逻辑,我们就需要自己定义一个接口,调用时,并实现这个接口。它的出现,则无需我们重复定义。

2.1 源码

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);


// 省略其他代码

}

看到上述代码,我们会发现内置了一个 R apply(T t),什么意思呢?

Applies this function to the given argument. (给定参数T 调用该函数返回R)

2.2 结合

既然Function<T,R>可以允许我们自定一个函数,通过给定参数T返回结果R 那么,对应案例中,就是给定参数PageForm<FundProductForm> form,返回结果Result<PageVO<ProductVo>>。我们顺着这个思路,把上述代码,差异的部分提取一个函数,代码如下:

public Result<PageVO<ProductVo>> loadRecords(PageForm<FundProductForm> form, Function<PageForm<FundProductForm>,List<Product>> query) {
        List<ProductVo> productVos = Collections.emptyList();
        int count = 0;
        try {
            List<Product> products = query.apply(form);
            if (CollectionUtils.isEmpty(products)) {
                return Result.failInEmptyRecord(null);
            }
            Map<String, String> productTypeMap = diamondConfigProxy.queryProductType().stream().collect(Collectors.toMap(ProductTypeRe::getCode, ProductTypeRe::getName));
            productVos = new ProductVoConvertor().convertList(products, productTypeMap);
            count = fundProductService.getNotBindProductCount(form);
        }catch (Exception e){
            LOGGER.error("{}loadNotBindRecords加载数据异常,form={}",LOG_TITLE, JSON.toJSON(form),e);
            return  Result.fail(PageVO.newInstance(count,productVos));
        }
        return Result.suc(PageVO.newInstance(count,productVos));
    }

那么原先调用的方法,则修改如下:

/**
     * 分页查出当前资金方绑定产品列表
     * @param form
     * @return
     */
    @LogMonitor("资金方管理")
    public Result<PageVO<ProductVo>> loadBindRecords(PageForm<FundProductForm> form) {
        return loadRecords(form, arg -> fundProductService.selectBindProductByParams(form));
    }

    /**
     * 分页查出当前资金方尚未绑定产品列表
     * @param form
     * @return
     */
    @LogMonitor("资金方管理")
    public Result<PageVO<ProductVo>> loadNotBindRecords(PageForm<FundProductForm> form) {
        return loadRecords(form, arg -> fundProductService.selectNotBindProductByParams(form));
    }

是不是很简单,代码瞬间看起来清新了许多。

3.总结

Function<R,T> 函数通畅用于封装一个通用的函数,对于参数传入的参数T,返回结果R。对于日常中如果代码中只是调用一个函数的差异,比如查询数据库结果集是调用不同的接口,则可以通过它来实现封装。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值