Why does Collectors.toMap report value instead of key on Duplicate Key error?

后端 未结 5 1718
春和景丽
春和景丽 2020-11-30 13:31

This is really a question about a minor detail, but I\'m under the impression to get something wrong here. If you add duplicate keys using Collectors.toMap-method it throws

5条回答
  •  臣服心动
    2020-11-30 14:23

    If you have this problem and are forced to use Java 8 in your project, then you will have to create your own collector to get a meaningful error message.

    Below you can find an example of a collector which gives you a meaningful message similar to the one you would get with Java 9:

    private static class Something {
        private final String k;
        private final String v;
    
        public Something(String k, String v) {
            this.k = k;
            this.v = v;
        }
    }
    
    public static void main(String[] args) throws IOException, ParseException {
        List list = Arrays.asList(
                new Something("key1", "value1"),
                new Something("key2", "value2"),
                new Something("key3", "value3a"),
                new Something("key3", "value3b"));
    
        Collector> eloquentCollector =
                Collector.of(HashMap::new, (map, something) -> putUnique(map, something.k, something.v),
                        (m1, m2) -> { m2.forEach((k, v) -> putUnique(m1, k, v)); return m1; });
    
        Map map = list.stream().collect(eloquentCollector);
        System.out.println(map);
    }
    
    private static  void putUnique(Map map, K key, V v1){
        V v2 = map.putIfAbsent(key, v1);
        if(v2 != null) throw new IllegalStateException(
                String.format("Duplicate key '%s' (attempted merging incoming value '%s' with existing '%s')", key, v1, v2));
    }
    

    If you run this code, you will see the following error message pointing to the duplicate key and merge values:

    Duplicate key 'key3' (attempted merging values value3a and value3b)

    You should get the same exception message if you use in the example above parallelStream(), like e.g:

    Map map = list.parallelStream().collect(eloquentCollector);
    

    Credits to Holger for pointing out that the original answer was not OK for parallel streams.

提交回复
热议问题