dictionary - 如何使用Java 8中的方法引用进行Map合并?

标签 dictionary merge java-8 collectors

我有以下两种调用收集操作的形式,两者都返回相同的结果,但我仍然不能完全依赖方法引用并且需要 lambda。

<R> R collect(Supplier<R> supplier,
          BiConsumer<R,? super T> accumulator,
          BiConsumer<R,R> combiner)

为此,请考虑以下由 100 个随机数组成的流

List<Double> dataList = new Random().doubles().limit(100).boxed()
            .collect(Collectors.toList());

1) 以下示例使用纯 lambda

Map<Boolean, Integer> partition = dataList.stream()
            .collect(() -> new ConcurrentHashMap<Boolean, Integer>(),
(map, x) ->
{
    map.merge(x < 0.5 ? Boolean.TRUE : Boolean.FALSE, 1, Integer::sum);
}, (map, map2) ->
{
    map2.putAll(map);
});

2) 以下尝试使用方法引用,但第二个参数仍然需要 lambda

Map<Boolean, Integer> partition2 = dataList.stream()
            .collect(ConcurrentHashMap<Boolean, Integer>::new, 
(map, x) ->
{
    map.merge(x < 0.5 ? Boolean.TRUE : Boolean.FALSE, 1, Integer::sum);
}, Map::putAll);

在此示例中,如何重写 java 8 中的collect方法的第二个参数以使用方法引用而不是 lambda?

System.out.println(partition.toString());
System.out.println(partition2.toString());
{false=55, true=45}
{false=55, true=45}

最佳答案

如果您有一个现有方法完全执行预期的操作,则方法引用是一个方便的工具。如果您需要调整或附加操作,则没有特殊的方法引用语法来支持这一点,除非您将 lambda 表达式视为该语法。

当然,您可以在类中创建一个新方法来执行所需的操作,并创建对其的方法引用,当代码复杂性增加时,这是正确的方法,因为这样,它将获得一个有意义的名称并变得可测试。但对于简单的代码片段,您可以使用 lambda 表达式,这只是获得相同结果的更简单的语法。从技术上讲,没有什么区别,只是编译器生成的持有 lambda 表达式主体的方法将被标记为“合成”。

在您的示例中,您甚至不能使用 Map::putAll 作为合并函数,因为这会覆盖第一个 map 的所有现有映射,而不是合并值。

正确的实现应该是这样的

Map<Boolean, Integer> partition2 = dataList.stream()
    .collect(HashMap::new, 
             (map, x) -> map.merge(x < 0.5, 1, Integer::sum),
             (m1, m2) -> m2.forEach((k, v) -> m1.merge(k, v, Integer::sum)));

但你不需要自己实现它。 Collectors 类中已经提供了适当的内置收集器:

Map<Boolean, Long> partition2 = dataList.stream()
    .collect(Collectors.partitioningBy(x -> x < 0.5, Collectors.counting()));

关于dictionary - 如何使用Java 8中的方法引用进行Map合并?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52430447/

相关文章:

python - 使用列表理解绘制存储在字典列表中的数据

python - 如何将 Maya 节点层次结构存储到 Python 字典中

java - JPA 合并实体管理器

merge 成功后 Git rebase 冲突?

Java 逻辑根据收到的代码更新字符串

具有混合类型的 Swift 字典(可选和非可选)

r - 基于R中的不同值合并数据帧

lambda - 将 ValidationSupport lambda 调用转换为方法引用

java - 使用大型并行 Java 8 流时如何防止堆空间错误

c++ - 带有映射迭代器的错误访问内存