java为什么不支持收集器。toMap报告值而不是重复键错误上的键?
这确实是一个关于一个小细节的问题,但我的印象是这里出了问题。如果使用Collectors.toMap-method添加重复键,它会抛出一个异常,并显示消息“duplicate key”。为什么报告的是值而不是键?或者两者都有?这真是误导,不是吗
这里有一个小测试来证明这种行为:
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<Something> list = Arrays.asList(
new Something("key1", "value1"),
new Something("key2", "value2"),
new Something("key3", "value3a"),
new Something("key3", "value3b"));
Map<String, String> 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;
}
}
}
# 1 楼答案
如果您遇到了这个问题,并且被迫在项目中使用Java8,那么您必须创建自己的收集器以获得有意义的错误消息
下面是一个收集器示例,它给您提供了一条与Java 9类似的有意义的消息:
如果运行此代码,将看到以下错误消息,指向重复键和合并值:
如果在上面的示例中使用
parallelStream()
,您应该会得到相同的异常消息,例如:感谢Holger指出原始答案对并行流不适用
# 2 楼答案
# 3 楼答案
正如其他答案已经指出的那样,这是一个将在Java9中修复的错误。这个错误产生的原因是} ,后者具有签名
toMap
依赖于^{如果
key
之前没有映射,则此方法将插入key
-value
映射,否则,将计算remappingFunction
以计算新值。因此,如果不允许重复密钥,那么直接提供一个remappingFunction
,它将无条件地抛出一个异常,您就完成了。但是…如果你查看函数签名,你会注意到这个函数只接收要合并的两个值,而不是键当为Java 8实现^{} 时,人们忽略了第一个参数是而不是键,但更糟糕的是,它不是直接修复的
如果您试图使用overloaded ^{} collector 提供一个替代合并,您会注意到。此时,键值根本不在范围内。Java 9开发人员必须更改整个
toMap
实现,才能提供一条异常消息来报告受影响的密钥# 4 楼答案
在Java8中,不允许一次将两个流(或同一个流迭代两次)中的重复值合并到映射中。 您可以使用收集器。分组方式&收藏家。映射将结果合并到
Map<Object, Set<Object>>
或Map<Object, List<Object>>
进行处理