Collectors.toMap具有相同的键(打印相同的键)

我有这个代码来获取地图:

List myList = myMethod.getList(); myList.stream().collect( Collectors.toMap( MyObject::getKey, MyObject::getValue, (e1, e2) -> { System.out.println("Duplicate keys !!!"); return e1; }, LinkedHashMap::new ) ); 

我如何用重复键打印消息“重复键”?

我如何用重复键打印消息“重复键”?

使用当前代码,您将获得消息“Duplicate keys”,其中包含MyObject列表,其中包含至少2个MyObject实例,它们具有相同的对象作为getKey()值,例如Arrays.asList(new MyObject("foo", "bar"), new MyObject("foo", "bar2"))

如何获得相应的密钥?

到目前为止,无法获取相应的密钥,您当前从合并函数获得的内容实际上是使用相同的密钥映射的2个值,这些密钥需要合并以仅保留相应密钥的一个值。

您的问题是Java 9中已修复的已知问题,请参阅JDK-8040892了解更多详细信息,相应的修复将允许我们从合并函数中获取要合并的键和值。

另请参见为什么Collectors.toMap在重复键错误上报告值而不是键?

如本回答所述 ,这是一个已知的问题,将在Java 9中修复 – 至少对于不接受合并函数的toMap收集器而言。

由于合并函数只接收要合并的两个值,并且签名不容易更改,因此无法解决这些重载方法。 遗憾的是,没有toMap收集器接受没有显式合并function的Map Supplier ,因此除非在发布之前这种情况发生变化,否则将无法修复应返回LinkedHashMap的场景。

所以解决方案是实现自己的收集器。 然后,您不必等待Java 9,也不必冒险失望。

 static > Collector toMap( Function keyExtractor, Function valueExtractor, Supplier mapSupplier) { return Collector.of(mapSupplier, (m, t) -> putUnique(m, keyExtractor.apply(t), valueExtractor.apply(t)), (m1,m2)-> { m2.forEach((k, v) -> putUnique(m1, k, v)); return m1; } ); } 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 (values %s and %s)", key, v1, v2)); } 

您可以将此收集器用作

 LinkedHashMap map = myList.stream() .collect(toMap(MyObject::getKey, MyObject::getValue, LinkedHashMap::new)); 

或使用限定的MyCollector.toMap ,指的是放置该自定义收集器的类。