lambda的toMap是不是要注意点,线上事故

文章讨论了在Java8中使用StreamAPI的toMap方法时可能出现的主键冲突问题,导致IllegalStateException。当Map的key有重复值时,Collectors.toMap默认会抛出异常。解决办法是提供一个自定义的冲突处理函数(mergeFunction),例如覆盖旧值。作者建议在使用toMap时要注意这个问题,要么指定mergeFunction,要么确保key的唯一性,以避免意外的异常。

异常回顾

先看代码:

dbTaxiDrivers.ifPresent((drivers) -> {
            map.putAll(drivers.stream()
                .collect(Collectors.toMap(TaxiDriverInfo::getOperationId, item -> item)));
        });

相信很多为了减少2层for循环,for循环查sql,都会定义Map<String, Object>的类型,去减少嵌套

而java8提供了toMap,简直就是方便。

相信很多人都用过这个方法,那这段代码到底有没有问题?我最开始以为没有,不就是转换成map吗,能有什么问题,至到吃过亏了,才知道其它有个坑在这,稍不注意就掉坑了。

这不,前阵子有个同事又踩坑了,还是大坑。

上线后,第一天,相安无事

第二天,线上狂报警:XX模块迭0,一看日志,出现了类似如下错误:

java.lang.IllegalStateException: Duplicate key a

    at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
    at java.util.HashMap.merge(HashMap.java:1254)
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)

主键冲突!!!

如果Map的key里面有重复值,Collectors.toMap会报主键重复的错误

啥,我怎么知道key重复

源码追踪

源码中看下报错的异常。

 根据堆栈,得到报错的地方,HashMap里面的mergeFunction

从上面的代码里面可以看出,如果有值重复,则会执行mergeFunction,默认为抛出异常。

那么如果出现主键重复的情况,该如何处理呢?

指定冲突处理函数

默认的处理函数是抛出函数,也就是异常原因

 重写一下上面那个例子

List<String> list = Lists.newArrayList();
        list.add("a");
        list.add("a");

        Map<String, String> map = list.stream().collect(Collectors.toMap(a -> a, Function.identity(), (oldValue, newValue) -> newValue));

 运行上面的例子,将会正常运行,在上面指定了mergeFunction:(oldValue, newValue) -> newValue,表示以新值覆盖旧值!

这样,开发者又可以主动处理这种情况了。

总之一句话,用toMap要小心,主键重复处理的情况,如果有重复,要么指定mergeFunction,要么控制不要重复,否则就半夜应急吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值