我有以下两种调用收集操作的形式,两者都返回相同的结果,但我仍然不能完全依赖方法引用并且需要 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/