关于list集合拷贝工具类

本文探讨了在Java开发中进行Bean拷贝时,Hutool的BeanUtil类与Orika框架的性能差异。虽然Hutool工具库方便易用,但其大量使用反射可能影响性能。Orika作为一个专业的映射框架,性能更优,但在某些情况下可能出现父类拷贝问题。此外,文章还分享了一种自定义的BeanUtil实现,通过缓存提高拷贝效率。

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

通常大家都用Hutool工具的BeanUtil类来进行list集合拷贝:

官网:Hutool — 🍬A set of tools that keep Java sweet.

Hutool是一个小而全的Java工具类库,既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;

  • Web开发
  • 与其它框架无耦合
  • 高度可替换

BeanUtil使用实例:

    private void copyDemo(User user, List<User> list) {
        
        //hutool list拷贝
         List<UserBO> listHutool =  cn.hutool.core.bean.BeanUtil.copyToList(list,UserBO.class);
        //hutool 对象拷贝
         UserBO test = cn.hutool.core.bean.BeanUtil.copyProperties(user,UserBO .class);

        //BeanUtil 对象拷贝 自己封装的BeanUtil方法
        UserBO userBO = BeanUtil.copyProperties(user, UserBO.class);

        //BeanUtil list拷贝
        List<UserBO> list2 = BeanUtil.copyPropertiesOfList(list, UserBO.class);
    }

但是,Hutool的BeanUtil类使用了大量反射,用他来进行list拷贝,性能略有影响,如果对性能有所要求,可以考虑使用Orika,来进行list拷贝。

Orika 是一个 Java Bean 映射框架,可以将两个不同类对象进行转换,特别是不同API时,常常会遇到实体转换。

关于Orika性能为什么快的源码分析:Orika源码分析:性能为什么这么快 - 简书

关于Orika使用:orika core工具对实体(Bean)进行深度拷贝 - miaoying - 博客园

在实际开发中,进行不同对象转换时,可以根据自己的需要选择转换工具类。

朋友们,发现了Orika的坑,Orika会偶发性出现父类拷贝不了的情况,看了源码也没看出个所以然,最后还是用了BeanUtil

个人封装的BeanUtil

public class BeanUtil {

    private BeanUtil() {
        //do nothing
    }

    public static final Map<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();

    public static final Map<String, ConstructorAccess> CONSTRUCTOR_ACCESS_CACHE = new ConcurrentHashMap<>();

    public static void copyProperties(Object source, Object target) {
        BeanCopier copier = getBeanCopier(source.getClass(), target.getClass());
        copier.copy(source, target, null);
    }

    private static BeanCopier getBeanCopier(Class sourceClass, Class targetClass) {
        String beanKey = generateKey(sourceClass, targetClass);
        BeanCopier copier = null;
        if (!BEAN_COPIER_CACHE.containsKey(beanKey)) {
            copier = BeanCopier.create(sourceClass, targetClass, false);
            BEAN_COPIER_CACHE.put(beanKey, copier);
        } else {
            copier = BEAN_COPIER_CACHE.get(beanKey);
        }
        return copier;
    }

    /**
     * 两个类的全限定名拼接起来构成Key
     *
     * @param sourceClass
     * @param targetClass
     * @return
     */
    private static String generateKey(Class<?> sourceClass, Class<?> targetClass) {
        return sourceClass.getName() + targetClass.getName();
    }

    public static <T> T copyProperties(Object source, Class<T> targetClass) {
        T t = null;
        try {
            t = targetClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BeanCopyException(String.format("Create new instance of %s failed: %s", targetClass, e.getMessage()));
        }
        copyProperties(source, t);
        return t;
    }

    public static <T> List<T> copyPropertiesOfList(List<?> sourceList, Class<T> targetClass) {
        if (sourceList == null || sourceList.isEmpty()) {
            return Collections.emptyList();
        }

        ConstructorAccess<T> constructorAccess = getConstructorAccess(targetClass);
        List<T> resultList = new ArrayList<>(sourceList.size());
        for (Object o : sourceList) {
            T t = null;
            try {
                t = constructorAccess.newInstance();
                copyProperties(o, t);
                resultList.add(t);
            } catch (Exception e) {
                throw new BeanCopyException(e);
            }
        }
        return resultList;
    }

    private static <T> ConstructorAccess<T> getConstructorAccess(Class<T> targetClass) {
        ConstructorAccess<T> constructorAccess = CONSTRUCTOR_ACCESS_CACHE.get(targetClass.getName());
        if (constructorAccess != null) {
            return constructorAccess;
        }
        try {
            constructorAccess = ConstructorAccess.get(targetClass);
            constructorAccess.newInstance();
            CONSTRUCTOR_ACCESS_CACHE.put(targetClass.toString(), constructorAccess);
        } catch (Exception e) {
            throw new BeanCopyException(String.format("Create new instance of %s failed: %s", targetClass, e.getMessage()));
        }
        return constructorAccess;
    }
}

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值