找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1563

积分

0

好友

231

主题
发表于 16 小时前 | 查看: 2| 回复: 0

BeanUtils.copyProperties() 在 Java 开发中极大地简化了对象属性的拷贝工作。尽管它无法实现深拷贝,但对于 PO、VO、DTO 等对象间的浅层拷贝已经足够高效。然而,在实际应用场景中,它仍存在一些不尽如人意的地方。

其主要不足体现在以下几个方面:

①. 无法直接拷贝List集合
实际开发中,需要对整个列表进行数据转换的情况非常普遍,使用原生方法会导致大量重复的循环代码。

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

②. 简单查询转换不够简洁
对于一些仅需转换对象类型的简单查询,代码中仍需要显式地实例化目标对象。

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

③. 对函数式编程支持不友好
原生的拷贝方法没有返回值,在 Java 8 引入 Stream 和 Lambda 表达式后,这种设计不利于进行流畅的链式调用。为此,我们决定通过扩展 BeanUtils 类,封装一个更便捷的工具类

使用新的转换工具

我们将创建一个新的工具类 BeanConvertUtils。使用时,对象转换将变得非常简洁:

// 使用前
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))
 );
}

当需要拷贝整个列表时,操作同样简单:

// 使用前
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.converToList(dao.findAll(), Vo::new)
}

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

核心实现代码如下

/**
 * 转换对象工具
 *
 * @author bugpool
 */
public class BeanConvertUtils extends BeanUtils {

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

    /**
     * 转换对象
     *
     * @param source         源对象
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象
     */
    public static <S, T> T convertTo(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> convertListTo(List<S> sources, Supplier<T> targetSupplier) {
        return convertListTo(sources, targetSupplier, null);
    }

    /**
     * 转换对象
     *
     * @param sources        源对象list
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象list
     */
    public static <S, T> List<T> convertListTo(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;
    }

    /**
     * 回调接口
     *
     * @param <S> 源对象类型
     * @param <T> 目标对象类型
     */
    @FunctionalInterface
    public interface ConvertCallBack<S, T> {
        void callBack(S t, T s);
    }
}

性能考量

由于 BeanConvertUtils 本质上是对 BeanUtils 的一层封装,其性能与原方法几乎一致。理论上可能因为多了一层方法调用栈而有微小损耗,但这完全可以忽略不计。主要的性能开销依然取决于底层 BeanUtils.copyProperties() 的实现。

注意事项

这个工具类在项目中能显著提升编码效率,但有两点需要特别注意:

  • 深拷贝问题:此方法依然无法解决嵌套对象的深拷贝问题,关于BeanUtils的深拷贝限制需要另行了解。
  • 空值处理策略:当源对象 source 或目标对象供应方 targetSupplier 任一为 null 时,本工具类不会抛出异常,而是直接返回 null。这基于一种设计理念:是否允许转换空值应由调用方决定,工具类仅提供转换服务。



上一篇:C++多线程调试实战:分析日志打印后崩溃消失的并发问题
下一篇:高并发与高QPS的核心差异:系统性能瓶颈分析与优化策略
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 17:20 , Processed in 0.284923 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表