java 6种拷贝集合方式及其性能差异对比

测试背景
在项目中很多地方需要拷贝对象集合、A类型对象的集合转换到B类型这种操作,但是这种操作的完成是有各种写法的,每种写法的性能可能不一样,因此对比一下各个写法的性能差异,选择最优解。
对一个有1000个对象的List复制1000次
ActivityCouponVO 对象有35个字段,各类型都有

	/**
     * 集合大小
     */
    private int len = 1000;
    /**
     * 循环次数
     */
    private int loop = 1000;
	List<ActivityCouponVO> getList(int len){
     // ... 生成一千个这个对象的集合,且每个字段赋值了
}

测试方法完整代码示范如下,后续各种方式的代码只写一次复制的代码示意,不写外层循环和耗时打印这些了
在这里插入图片描述

ArrayList 构造方法拷贝

底层使用了Arrays.copyOf()方法,这个方法底层又用了System.arraycopy方法,这个方法是native方法,使用本地实现,(一般为c++),直接操作内存复制,效率高
注意:new ArrayList<>(list)、Arrays.copyOf()、System.arraycopy这三个都是浅拷贝!!!

List<ActivityCouponVO> list = getList(len);
ArrayList<ActivityCouponVO> activityCouponVOS = new ArrayList<>(list);

运行1000次耗时 1ms

for循环拷贝

这个直接add 对象 也是浅拷贝,拷贝的是对象的内存地址
如果要深拷贝则循环的时候每次new一个新的对象并复制属性值

			List<ActivityCouponVO> list = getList(len);
			List<ActivityCouponVO> collect = new ArrayList<>(len);
            for (ActivityCouponVO activityCouponVO : list) {
                collect.add(activityCouponVO);
            }

运行1000次耗时 14ms

Stream流 collect实现拷贝

浅拷贝

List<ActivityCouponVO> list = getList(len);
List<ActivityCouponVO> collect = list.stream().collect(Collectors.toList());

运行1000次耗时 54ms

Stream流+spring的BeanUtils实现拷贝

这种拷贝方式是第一层属性深拷贝,嵌套的对象是浅拷贝

List<ActivityCouponVO> list = getList(len);
List<ActivityCouponVO> activityCouponVOS = list.stream().map(o -> {
                ActivityCouponVO activityCouponVO = new ActivityCouponVO();
                BeanUtils.copyProperties(o, activityCouponVO);
                return activityCouponVO;
            }).collect(Collectors.toList());

运行1000次耗时 2468 ms

Hutool工具实现拷贝

这种拷贝方式是第一层属性深拷贝,嵌套的对象是浅拷贝

List<ActivityCouponVO> list = getList(len);
List<ActivityCouponVO> activityCouponVOS = BeanUtil.copyToList(list, ActivityCouponVO.class);

Hutool 5.7.13版本运行1000次耗时 64674 ms

(看了下源码是因为加锁了)

Hutool 5.8.24版本运行1000次耗时 15874 ms

(新版本里没有加锁了,而且还做了优化,例如properties缓存)

JSON序列化

完全深拷贝

JSONObject.parseArray(JSONObject.toJSONString(list), ActivityCouponVO.class);

运行1000次 耗时 3387 ms

结论

不需要深拷贝时建议使用
Arrays.copyOf()
System.arraycopy
这种本地实现的拷贝数组方式
深拷贝时可以使用for循环、stream流、BeanUtils工具等方式实现,但是要注意使用工具的时候看看工具的源码实现,有可能里面有锁,然后有性能的坑~

posted @ 2024-01-04 20:57  HumorChen99  阅读(113)  评论(0编辑  收藏  举报  来源