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

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

    • 1.问题复现
    • 2.解决方案

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  Collector> toMap(Function keyMapper,
                                    Function valueMapper)

public static  Collector> toMap(Function keyMapper,
                                    Function valueMapper,
                                    BinaryOperator mergeFunction) 

public static >  Collector toMap(Function keyMapper,
                                Function valueMapper,
                                BinaryOperator mergeFunction,
                                Supplier mapSupplier) 

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

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

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

Map 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)}

你可能感兴趣的:(Java,java,java-ee,开发语言)