改造BeanUtils,优雅实现List数据拷贝

共 4047字,需浏览 9分钟

 ·

2022-06-06 18:51

往期热门文章:

1、SpringBoot 启动时自动执行代码的几种方式,还有谁不会??

2、劲爆!Java 通用泛型要来了。。

3、如何写出让同事吐血的代码?

4、遭弃用的 Docker Desktop 放大招!宣布支持 Linux

5、IDEA公司再发新神器!超越 VS Code 骚操作!

文章来源:http://b.nxw.so/1661BT


目录
  • 前言

  • 使用

  • 性能

  • 提醒


前言


BeanUtils.copyProperties();确实为我们做了很多事情,虽然不能完美完成深拷贝,但是对于 po、vo、dto 的拷贝已经足够用了。但是其还是有一些不够完美的地方。


不足几点如下:


不能拷贝 list,而拷贝 list 的情况又大量存在,因此会有许多重复代码。

for (S source : sources) {
    T target = new T();
    copyProperties(source, target);
    list.add(target);
}


有一些简单的查询,仅仅需要转换一下 vo 也需要 new Vo()。

public Vo findById(Integer id) {
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
 return vo;
}


这种拷贝方式是没有返回值的,jdk8 支持 stream() 操作之后,支持不是很友好,不方便 lambda 表达式的使用,因此我们决定通过集成 BeanUtils 类,自己造一个方便用的轮子。


使用


我们将新创建一个轮子 BeanConvertUtils,使用如下,当我们要转换 po、vo 时,只需要:

// 使用前
public Vo findById(Integer id) {
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
 return vo;
}

// 使用后
public Vo findById(Integer id) {
 return BeanConvertUtils.converTo(dao.findById(id), Vo::new);
}

// 使用后,通过lambda表达式特殊处理个别字段
public Vo findById(Integer id) {
 return BeanConvertUtils.converTo(dao.findById(id), Vo::new
  (s, t) -> t.setName(s.getName))
 );
}


当我们要拷贝 list 的时候也很简单:

// 使用前
public List findAll() {
 List vos = new ArrayList();
 List pos = dao.findAll();
 for (Po po : Pos) {
     Vo vo = new Vo();
     BeanUtis.copyProperties(po, vo);
     vos.add(vo);
    }
 return vos;
}

// 使用后
public List findAll() {
 return BeanConvertUtils.converToList(dao.findAll(), Vo::new)
}

// 同样支持自定义lambda
public List findAll() {
 return BeanConvertUtils.converToList(dao.findAll(), Vo::new,
  (s, t) -> t.setName(s.getName))
 )
}


代码如下:

/**
 * 转换对象工具
 *
 * @author bugpool
 */

public class BeanConvertUtils extends BeanUtils {

    public static  T convertTo(S source, Supplier targetSupplier) {
        return convertTo(source, targetSupplier, null);
    }

    /**
     * 转换对象
     *
     * @param source         源对象
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param             源对象类型
     * @param             目标对象类型
     * @return 目标对象
     */

    public static  T convertTo(S source, Supplier targetSupplier, ConvertCallBack callBack) {
        if (null == source || null == targetSupplier) {
            return null;
        }

        T target = targetSupplier.get();
        copyProperties(source, target);
        if (callBack != null) {
            callBack.callBack(source, target);
        }
        return target;
    }

    public static  List convertListTo(List sources, Supplier targetSupplier) {
        return convertListTo(sources, targetSupplier, null);
    }

    /**
     * 转换对象
     *
     * @param sources        源对象list
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param             源对象类型
     * @param             目标对象类型
     * @return 目标对象list
     */

    public static  List convertListTo(List sources, Supplier targetSupplier, ConvertCallBack callBack) {
        if (null == sources || null == targetSupplier) {
            return null;
        }

        List list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T target = targetSupplier.get();
            copyProperties(source, target);
            if (callBack != null) {
                callBack.callBack(source, target);
            }
            list.add(target);
        }
        return list;
    }

    /**
     * 回调接口
     *
     * @param  源对象类型
     * @param  目标对象类型
     */

    @FunctionalInterface
    public interface ConvertCallBack<ST{
        void callBack(S t, T s);
    }
}


性能


由于只是 BeanUtils 的一个封装,跟原来的代码性能几乎差不多,如果要说差一点也没错,毕竟多了一层函数堆栈的调用,但是基本可以忽略不计。主要的性能还是由 BeanUtils 决定。


提醒


不知道大家对这个 BeanConvertUtils 工具类感觉怎么样,自己在项目中倒是大量使用,也很方便。


但是有两点要提醒:

  • 此方法依旧不能解决深层次的深拷贝问题,详细的可以 google 一下 BeanUtils 的深拷贝问题。
  • 如果 source 或者 targetSupplier 只要有一个为 null,本工具类不像 BeanUtils 一样抛出异常,而是返回 null,因为笔者认为调用方如果把 null 进行准换,那就是想转换为 null,为不为空应该由调用方自己负责。

最近热文阅读:

1、SpringBoot 启动时自动执行代码的几种方式,还有谁不会??
2、如何写出让同事吐血的代码?
3、遭弃用的 Docker Desktop 放大招!宣布支持 Linux
4、IDEA公司再发新神器!超越 VS Code 骚操作!
5、推荐好用 Spring Boot 内置工具类
6、五个刁钻的String面试问题及解答
7、IntelliJ平台将完全停止使用Log4j
8、神操作!我把 3000 行代码重构成 15 行!
9、我用Java几分钟处理完30亿个数据...
10、一款自动生成单元测试的 IDEA 插件
关注公众号,你想要的Java都在这里

浏览 41
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报