【问题标题】:Shortcut for mapping a Stream to a Map with an identity key使用标识键将 Stream 映射到 Map 的快捷方式
【发布时间】:2019-07-02 06:49:03
【问题描述】:

考虑以下通过将每个字符串映射到其长度并打印每个映射条目来处理字符串列表的示例代码

package com.dbenergie.ndm.bnb.business;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Application {

    public static void main(String[] args) {
        final List<String> strings = Arrays.asList("Hello", "World", "!");

        // 1
        final Map<String, Integer> stringCharacterCountMapping = strings.stream()
                .collect(Collectors.toMap(Function.identity(), String::length));

        stringCharacterCountMapping.entrySet().stream().forEach(System.out::println);
    }
}

现在,我个人觉得相当混乱或样板式的是使用Function.identity()(1)将每个流条目显式映射为映射的键,但到目前为止我发现的每个映射收集器都需要一个键映射器 -是否有一些我忽略的收集器,或者如果我需要这个,我是否必须定义我自己的收集器?有类似的东西会很方便

Collectors.toMap(String::length);

或类似的。有什么想法吗?

【问题讨论】:

  • toMap 没有定义键映射,是这个意思吗?
  • toMap 隐式使用流元素作为键。
  • 如果在文档中看到 (docs.oracle.com/javase/8/docs/api/java/util/stream/…) ,实际上有 3 个 Collectors.toMap 方法,每个方法都以 keyMapper 作为参数。所以没有它是不可能的。

标签: java java-stream


【解决方案1】:

There is no toMap method in the Collectors class that does not take a keyMapper. 我怀疑这是因为您传递的单个参数映射到的内容可能非常模棱两可。值还是键?

你可以自己轻松写出这样的收集器:

class MyCollectors {
    public static <K, U> Collector<K, ?, Map<K,U>> toMapWithValueWrapper(Function<? super K, ? extends U> valueMapper) {
        return Collectors.toMap(Function.identity(), valueMapper);
    }
}

请注意签名与Collectors.toMap 略有不同。只有 2 个通用参数。原始的Collectors.toMap 有3 - T(我们正在收集的类型)、K(键的类型)和U(值的类型)。由于您使用密钥的标识函数,密钥将始终具有与我们正在收集的类型相同的类型,因此T == K。因此,我们可以消除T

编辑:

正如 Holger 在 cmets 中建议的那样,我们不必强制 T == K,因为 T 可能是 K 的子类,您仍然可以使用标识函数从 T 映射到 K .因此,您可以使用:

class MyCollectors {
    public static <T extends K, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends U> valueMapper) {
        return Collectors.toMap(Function.identity(), valueMapper);
    }
}

如果您想允许收集到其键类型是您正在收集的类型的超类的地图。

【讨论】:

  • 看起来和我实现的快捷方式一模一样 - 遗憾地看到这个用例还没有出现,但很高兴看到这可以通过很少的代码来实现。
  • 我们可以消除T,但问题是我们是否应该这样做。如果我们使用&lt;T extends K&gt;,我们允许将更具体的元素流收集到具有更广泛键类型的映射中。这与我们使用Function&lt;? super K, ? extends U&gt; 而不是Function&lt;K, U&gt; 的原因相同……
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 2010-09-06
  • 1970-01-01
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-18
相关资源
最近更新 更多