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

编程入门 行业动态 更新时间:2024-10-13 10:27:57

改造BeanUtils<a href=https://www.elefans.com/category/jswz/34/1770208.html style=优雅实现List数据拷贝"/>

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

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

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

// 使用前
public List<Vo> findAll() {List<Vo> vos = new ArrayList();List<Po> pos = dao.findAll();for (Po po : Pos) {Vo vo = new Vo();BeanUtis.copyProperties(po, vo);vos.add(vo);}return vos;
}// 使用后
public List<Vo> findAll() {return BeanConvertUtils.toList(dao.findAll(), Vo::new)
}// 同样支持自定义lambda
public List<Vo> findAll() {return BeanConvertUtils.toList(dao.findAll(), Vo::new,(s, t) -> t.setName(s.getName)))
}

代码如下

package com.zyys.order.util;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.BeanUtils;import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;/*** 转换对象工具** @author jin*/
public class EntityUtils extends BeanUtils {public static <S, T> T toObject(S source, Supplier<T> targetSupplier) {return toObject(source, targetSupplier, null);}/*** 转换对象** @param source         源对象* @param targetSupplier 目标对象供应方* @param callBack       回调方法* @param <S>            源对象类型* @param <T>            目标对象类型* @return 目标对象*/public static <S, T> T toObject(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> 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 <S, T> List<T> toList(List<S> sources, Supplier<T> targetSupplier) {return toList(sources, targetSupplier, null);}/*** 转换对象** @param sources        源对象list* @param targetSupplier 目标对象供应方* @param callBack       回调方法* @param <S>            源对象类型* @param <T>            目标对象类型* @return 目标对象list*/public static <S, T> List<T> toList(List<S> sources, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {if (null == sources || null == targetSupplier) {return null;}List<T> 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;}public static <S, T> Page<T> toPage(Page<S> page, Supplier<T> targetSupplier) {return toPage(page,targetSupplier,null);}/**** @param page 源page对象* @param targetSupplier 目标对象供应方* @param callBack 回调方法* @param <S> 源对象类型* @param <T> 目标对象类型* @return*/public static <S, T> Page<T> toPage(Page<S> page, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {if (null == page || null == page.getRecords() || null == targetSupplier) {return null;}List<T> list = new ArrayList<>();for (S source : page.getRecords()) {T target = targetSupplier.get();copyProperties(source, target);if (callBack != null) {callBack.callBack(source, target);}list.add(target);}return new Page<T>(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(list);}/**** @param list 源数据* @param getter 取值* @param <S> 源对象类型* @param <T> 目标对象类型* @return*/public static <S, T> Set<T> toSet(List<S> list, Function<S, T> getter){return list.stream().map(getter).filter(Objects::nonNull).collect(Collectors.toSet());}/*** 按指定属性分组* @param list 待分组的列表* @param classifier 用于分组的 Function* @param <T> 列表元素类型* @param <K> 分组键类型* @return 分组后的 Map*/public static <T, K> Map<K, List<T>> groupBy(List<T> list, Function<T, K> classifier) {return list.stream().collect(Collectors.groupingBy(classifier));}/*** 回调接口** @param <S> 源对象类型* @param <T> 目标对象类型*/@FunctionalInterfacepublic interface ConvertCallBack<S, T> {void callBack(S t, T s);}}
                                   性能

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

                                   提醒     

①此方法依旧不能解决深层次的深拷贝问题,详细的可以 google 一下 BeanUtils 的深拷贝问题。

②如果 source 或者 targetSupplier 只要有一个为 null,本工具类不像 BeanUtils 一样抛出异常,而是返回 null,因为笔者认为调用方如果把 null 进行准换,那就是想转换为 null,为不为空应该由调用方自己负责。

更多推荐

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

本文发布于:2024-03-14 14:31:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1736679.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:优雅   数据   BeanUtils   List

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!