写点什么

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

作者:方明
  • 2021 年 12 月 24 日
  • 本文字数:1605 字

    阅读完需:约 5 分钟

关于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)}
复制代码


发布于: 4 小时前
用户头像

方明

关注

不求有多辉煌,但求无愧过往 2019.02.15 加入

Java 后端,没事侃侃

评论

发布
暂无评论
关于Stream转Map的Duplicate key异常处理