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

Tim*_*the 13 java java-8 java-stream collectors

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

这是一个证明行为的小测试:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Tun*_*aki 17

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

String.format("Duplicate key %s (attempted merging values %s and %s)", k, u, v)
Run Code Online (Sandbox Code Playgroud)

其中k是重复键,u并且v是映射到同一键的两个冲突值.


Hol*_*ger 7

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

V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
Run Code Online (Sandbox Code Playgroud)

如果没有先前的映射,则此方法将插入key- valuemapping,key否则remappingFunction将评估计算新值.因此,如果不允许重复密钥,那么直接提供一个remappingFunction无条件抛出异常的密钥,就完成了.但是......如果你看一下函数签名,你会注意到这个函数只接收要合并的两个,而不是.

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

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