• Java集合对象拷贝,使用JDK 8 的函数式接口封装org.springframework.beans.BeanUtils工具类实现


    需求描述:在进行数据同步时需要把SQLserver的数据表同步到MySQL的数据库表,有的表字段一样,但有的却字段类型不一样,需要进转换单独的转换,所以写了一个工具类实现,少写代码。

    1、定义一个函数式接口

    函数式接口里包含默认方法,这里我们定义默认回调方法。

    1. /**
    2. * 集合数据拷贝工具类扩展回调函数
    3. *
    4. * @author QC
    5. * @version V1.0
    6. * @since 2022-08-14
    7. */
    8. @FunctionalInterface
    9. public interface BeanUtilCopyCallBack {
    10. /**
    11. * 定义默认回调方法
    12. *
    13. * @param target 目标对象
    14. * @param source 源对象
    15. */
    16. void callBack(S source, T target);
    17. }

    2、封装一个工具类BeanUtilCopy.java

    1. import java.util.ArrayList;
    2. import java.util.List;
    3. import java.util.function.Supplier;
    4. import org.springframework.beans.BeanUtils;
    5. /**
    6. * 集合数据拷贝工具类封装
    7. *
    8. * @author QC
    9. * @version V1.0
    10. * @since 2022-08-14
    11. */
    12. public class BeanUtilCopy extends BeanUtils {
    13. /**
    14. * 集合数据的拷贝
    15. *
    16. * @param sources: 数据源类
    17. * @param target: 目标类::new(eg: UserVO::new)
    18. * @return list 目标数据对象列表
    19. */
    20. public static List copyListProperties(List sources, Supplier target) {
    21. return copyListProperties(sources, target, null);
    22. }
    23. /**
    24. * 带回调函数的集合数据的拷贝(可自定义字段拷贝规则)
    25. *
    26. * @param sources: 数据源类
    27. * @param target: 目标类::new(eg: UserVO::new)
    28. * @param copyCallBack: 回调函数 用于扩展修改字段数据类型,比如int改为string
    29. * @return list 目标数据对象列表
    30. */
    31. public static List copyListProperties(List sources, Supplier target, BeanUtilCopyCallBack copyCallBack) {
    32. List list = new ArrayList<>(sources.size());
    33. for (S source : sources) {
    34. T targetData = target.get();
    35. copyProperties(source, targetData);
    36. list.add(targetData);
    37. if (copyCallBack != null) {
    38. copyCallBack.callBack(source, targetData); // 回调
    39. }
    40. }
    41. return list;
    42. }
    43. }

    通过如上方法,基本实现了集合的拷贝,但是从返回结果我们可以发现:属性不同的字段无法拷贝。比如:UserDO.java 和UserVO.java 最后一个字段sn类型不一样,分别是:Integer/String

    使用案例如下:

     通过这个扩展就基本可解决各种类型转换了,该方法是我用的最多的方案,这里简单封装下,可以方便集合类型对象的拷贝,平常使用基本够用,仅供参考。

    1. /**
    2. * 同步到 Mysql-master(yth-yjt) 库
    3. *
    4. * @param originalData SQL Server-gwyj 库原始数据
    5. */
    6. private void executeMasterSync(List originalData) {
    7. //查询目标库是否存在数据
    8. List originalDataIDs = originalData.stream().filter(Objects::nonNull)
    9. .map(entity -> String.valueOf(entity.getSn())).collect(Collectors.toList());
    10. List originalDatas = targetStMntrltmService.lambdaQuery()
    11. .in(StMntrltmEntity::getSn, originalDataIDs)
    12. .orderByDesc(StMntrltmEntity::getSn).list();
    13. Set ids = originalDatas.stream().filter(Objects::nonNull).map(StMntrltmEntity::getSn).collect(Collectors.toSet());
    14. //转换为目标库实体
    15. List targetData = BeanUtilCopy.copyListProperties(originalData, StMntrltmEntity::new, (originalObj, targetObj) -> {
    16. targetObj.setSn(String.valueOf(originalObj.getSn()));//转换源数据的主键ID为String类型和目标表保持一致
    17. targetObj.setTm(DateUtils.dateCovertLocalDateTime(originalObj.getTm()));//date转localDateTime
    18. if (Objects.nonNull(originalObj.getOvvlu()))
    19. targetObj.setOvvlu(BigDecimal.valueOf(originalObj.getOvvlu()));//double 转 BigDecimal
    20. if (Objects.nonNull(originalObj.getVlu()))
    21. targetObj.setVlu(BigDecimal.valueOf(originalObj.getVlu()));//double 转 BigDecimal
    22. if (Objects.nonNull(originalObj.getVlu1()))
    23. targetObj.setVlu1(BigDecimal.valueOf(originalObj.getVlu1()));//double 转 BigDecimal
    24. });
    25. Map> partitioningMap = targetData.stream()
    26. .collect(Collectors.partitioningBy(entity -> ids.contains(entity.getSn())));//数据分割,包含的分为updateData,未包含的分为insertData
    27. List insertData = partitioningMap.get(false);
    28. List updateData = partitioningMap.get(true);
    29. if (!CollectionUtils.isEmpty(updateData)) {
    30. targetStMntrltmService.saveOrUpdateBatch(updateData);
    31. }
    32. if (!CollectionUtils.isEmpty(insertData)) {
    33. targetStMntrltmService.saveBatch(insertData);
    34. }
    35. }

    其中用到了很多Java8新的写法,比如使用流来处理数据列表,::拉姆达表达式的简写,拉姆达表达式,集合的分组等等。

    扩展知识:对象的拷贝

    对象拷贝概念

    Java中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型,引用类型包括类、接口、数组等复杂类型。

    对象拷贝分为浅拷贝(浅克隆)深拷贝(深克隆)

    浅拷贝与深拷贝差异

     


    参考文献:

    0、Java Bean Copy 性能大比拼 - 掘金

    1、对象属性拷贝常用的四种方式(总结出最高效率)_伏加特遇上西柚的博客-CSDN博客_java对象拷贝主要有四种方法

  • 相关阅读:
    打开Outlook报错修复
    Glide系列(四) — Glide缓存流程分析
    使用Redis查询数据库数据增加访问速度小案例
    【无标题】
    【userfaultfd】2021强网杯notebook
    Android手机保持屏幕常亮
    大数据Hadoop高可用
    nacos简单使用
    电脑桌面图标不见了怎么回事?正确的找回图标的2个方案
    视频号视频下载教程,为视频博主提供的PC电脑版下载方法
  • 原文地址:https://blog.csdn.net/qq_35624642/article/details/126332515