关于Stream转Map的Duplicate key异常处理

关于Stream转Map的Duplicate key异常处理

1.问题复现

先初始化一个 School 的集合,然后将该集合转成一个 Map,key 为 id, value 为 name。
:学校的 id 设置为重复的。
上代码

public static void main(String[] args) {
        List<School> schoolList = Lists.newArrayList(
                new School("1", "a"),
                new School("2", "b"),
                new School("1", "c")
        );
        Map<String, School> schoolMap = schoolList.stream().collect(Collectors.toMap(School::getId, dic -> dic));
        System.out.println(schoolMap);
    }

    @Data
    @AllArgsConstructor
    static class School implements Serializable {
        private String id;
        private String name;
    }

运行以上代码,控制台会出现以下错误:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key StreamTest.School(id=1, name=a)
	at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
	at java.util.HashMap.merge(HashMap.java:1245)
	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:1374)
	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)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
	at com.iflytek.edu.udp.web.admin.manager.StreamTest.main(StreamTest.java:24)

原因就是转换为 map 的时候 key 重复了。

2.解决方案

对于以上问题,是因为我们使用的方法不对,java8 的 Collectors 的 toMap 有三个重载方法:

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper)

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper,
                                    BinaryOperator<U> mergeFunction) 

public static <T, K, U, M extends Map<K, U>>  Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) 

上面的代码使用的就是第一个,我们看下该方法的注释就明白了:

返回一个将元素累积到 Map 中的收集器,其键和值是将提供的映射函数应用于输入元素的结果。
如果映射的键包含重复项(根据 Object.equals(Object)),则在执行集合操作时会抛出 IllegalStateException。 如果映射的键可能有重复项,请改用 toMap(Function, Function, BinaryOperator)。

所以答案就在里面,如果有映射的键有重复项就会报错,我们应该使用第二个方法,所以上面的代码我们略作修改即可,当碰到相同的键时,用后面的 value 覆盖前面的。

Map<String, School> schoolMap = schoolList.stream().collect(Collectors.toMap(School::getId, dic -> dic, (oldValue, newValue) -> newValue));

代码跑起来,打印结果如下:

{1=StreamTest.School(id=1, name=c), 2=StreamTest.School(id=2, name=b)}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值