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

这真是一个关于细微问题的问题,但我的印象是在这里弄错了。 如果使用Collectors.toMap-method添加重复键,则会抛出带有“重复键”消息的exception。 为什么报告的价值而不是关键? 甚至两个? 这真是误导,不是吗?

这是一个certificate行为的小测试:

import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class TestToMap { public static void main(String[] args) { List list = Arrays.asList( new Something("key1", "value1"), new Something("key2", "value2"), new Something("key3", "value3a"), new Something("key3", "value3b")); Map map = list.stream().collect(Collectors.toMap(o -> o.key, o -> o.value)); System.out.println(map); } private static class Something { final String key, value; Something(final String key, final String value){ this.key = key; this.value = value; } } } 

这被报告为一个错误,请参阅JDK-8040892 ,并在Java 9中修复。阅读提交修复此问题 ,新的exception消息将是

 String.format("Duplicate key %s (attempted merging values %s and %s)", k, u, v) 

其中k是重复键, uv是映射到同一个键的两个冲突值。

正如其他答案已经陈述的那样,这是一个将在Java 9中修复的错误。错误产生的原因是, toMap依赖于具有签名的Map.merge

 V merge(K key, V value, BiFunction remappingFunction) 

如果没有先前的key映射,则此方法将插入keyvalue映射,否则,将评估remappingFunction以计算新值。 因此,如果不允许重复键,则可以直接提供一个无条件抛出exception的remappingFunction ,然后就完成了。 但是……如果你看一下函数签名,你会注意到这个函数只接收要合并的两个 ,而不是

throwingMerger为Java 8实现时,忽略了第一个参数不是关键,但更糟糕的是,修复它并不是直接的。

如果您尝试使用重载的toMap收集器提供替代合并,您会注意到。 此时关键值不在范围内。 Java 9开发人员不得不为无重复的情况更改整个toMap实现,以便能够提供报告受影响密钥的exception消息…

这是Jdk 8中的一个已知错误。抛出的消息应该显示至少两个存在键冲突的值,或者理想情况下显示发生冲突的键。 附件是相同的链接