双括号初始化(double brace initialization)踩坑记录

场景:系统中有两个服务A和B,A服务中需要调用服务B中的批量删除的接口

服务B批量删除接口的入参

public class BatchOpVO implements Serializable {
    private String opIds;
}

 服务B的方法

public ServiceResponse delete(BatchOpVO batchOpVO ) {
    return ServiceResponse.success(manager.delete(batchOpVO));
}

 在服务A中的调用

@PostMapping(path = "/{op_id:\\d+}/actions/delete")
public ServiceResponse delete(@PathVariable("op_id") String opId) {
    BatchOpVO batchOpVO = new BatchOpVO(){{
        setOpIds(opId);
    }});
    return serviceB.delete(batchOpVO)
}

然后测试服务A的删除接口,调用失败,抛出异常

Caused by: java.lang.UnsupportedOperationException -    at com.taobao.pandora.service.sharedclass.LazyClassCacheMap.entrySet(LazyClassCacheMap.java:126) -    at com.taobao.hsf.com.caucho.hessian.io.MapSerializer.writeObject(MapSerializer.java:95) -    at com.taobao.hsf.com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:421) -    at com.taobao.hsf.com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:293) -    ... 175 more

序列化异常,第一想到的是,maven二方依赖包版本不同导致的,查看了使用的版本,重新将服务B deploy,服务A再更新依赖,做了一切保证版本同步的操作,依然报错,这种删除的接口以前也写过很多次了,想到唯一不同的就是初始化BatchOpVO的写法,我试着修改的初始化方式

在服务A中的调用(修改后的)

@PostMapping(path = "/{op_id:\\d+}/actions/delete")
public ServiceResponse delete(@PathVariable("op_id") String opId) {
    BatchOpVO batchOpVO = new BatchOpVO();
    batchOpVO.setOpIds(opId);
    return serviceB.delete(batchOpVO)
}

测试通过,那这两种方式有什么区别呢

搜到一篇关于讲双括号初始化的文章,才了解到,这样的创建方式,创建的是该类的匿名子类的实例,自然也就序列化失败了

上面的文章中还提到,这种方式的效率问题,这种方式会产生匿名类的class文件,效率会低,感觉有道理,但评论中又有人说

双花括号是节省效率的,List 自增机制对效率的影响尤为重要,以 ArrayList为例,初始默认空间为 10,每次自增为其 1.5 倍 + 1,就是 16、25...,所用空间较少时,ArrayList需频繁的自我复制来进行自增。当使用双花括号,取 ArrayList某个较大的自增临界点进行测试时,会发现在自增前使用 add方法,效率比在双花括号外 add 快 1/3 左走,但当空间增加到触发自增时,由双花括号内触发的自增效率,比双花括号外触发的自增要慢很多很多。当所用空间较少,ArrayList 频繁自增,由双花括号内触发的自增,损耗性能较大,当所用空间越来越多,双花括号内使用 add 方法,节省性能越多。若使用双花括号当自增达到某一临界值时,add 所节省的性能便会远远大于自增所消耗的性能,当然这个临界值会很大,所以当所占空间较少时,使用带有自我复制进行自增的集合来测试双花括号是不准确的。您若用真实实体对象就轻松多了

我看得不是很明白,但是最后说可以用真实的对象测试,我试了下,效率上基本没什么差别

测试代码

Long start = System.currentTimeMillis();
        for (int i=0;i<10000000;i++){
           BlogVo blogVo = new BlogVo(){{
                setTitle("标题");
                setContent("内容");
            }};
        }
        System.out.println(System.currentTimeMillis() - start);
Long start = System.currentTimeMillis();
       for (int i=0;i<10000000;i++){
            BlogVo vo = new BlogVo();
            vo.setTitle("标题");
            vo.setContent("内容");
        }
        System.out.println(System.currentTimeMillis() - start);

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值