【问题标题】:Collectors.toMap with same keys(print same key)Collectors.toMap 具有相同的键(打印相同的键)
【发布时间】:2017-04-07 07:32:53
【问题描述】:

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

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

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

【问题讨论】:

  • 我想用键值写入控制台消息“重复键”+,但我不知道该怎么做

标签: java java-8 collectors


【解决方案1】:

正如 this answer 中所解释的,这是一个已知问题,将在 Java 9 中修复 - 至少对于不接受合并函数的 toMap 收集器而言。

由于合并函数只接收要合并的两个值,并且签名不能轻易更改,因此这些重载方法目前还没有修复。不幸的是,没有toMap 收集器接受Map Supplier 而没有明确的合并功能,因此除非在发布之前这会发生变化,否则将无法解决您应该返回LinkedHashMap 的场景。

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

static <T, K, V, M extends Map<K, V>> Collector<T, ?, M> toMap(
    Function<T, K> keyExtractor, Function<T, V> valueExtractor, Supplier<M> 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 <K,V> void putUnique(Map<K,V> 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<KeyType, ValueType> map = myList.stream()
    .collect(toMap(MyObject::getKey, MyObject::getValue, LinkedHashMap::new));

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

【讨论】:

  • 谢谢,收集器界面对我来说有点不清楚,这是学习它的好方法!
【解决方案2】:

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

使用您当前的代码,您将收到带有 MyObject 列表的消息“重复键”,其中包含至少 2 个 MyObject 实例,这些实例具有与 getKey() 相同的对象,例如 Arrays.asList(new MyObject("foo", "bar"), new MyObject("foo", "bar2")) .

如何获取对应的key?

到现在还不能得到对应的key,你现在从merge函数中得到的其实是2个映射到同一个key的值,需要合并为对应的key只保留一个值。

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

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

【讨论】:

  • 请注意,该修复只会影响toMap 收集器,而没有明确的合并功能。由于仍然没有toMap 收集器接受没有自定义合并功能的自定义地图供应商,您仍然无法使用显式地图类型(如LinkedHashMap)并同时报告重复键......
猜你喜欢
  • 2022-08-05
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 2019-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多