[英]Java8 stream.reduce() with 3 parameters - getting transparency
我编写这段代码是为了将单词列表减少到以“A”开头的单词数量。 我写它只是为了学习 Java 8,所以我想更好地理解它[免责声明:我意识到这可能不是编写此代码的最佳方式; 仅供练习!】
Long countOfAWords = results.stream().reduce(
0L,
(a, b) -> b.charAt(0) == 'A' ? a + 1 : a,
Long::sum);
中间参数/lambda(称为累加器)似乎能够在没有最终“组合器”参数的情况下减少完整列表。 事实上,Javadoc 实际上说:
{@code accumulator} 函数充当融合的映射器和累加器,* 有时比单独的映射和归约更有效,* 例如当知道先前减少的值可以让您避免 * 某些计算时。
[来自作者的编辑] -以下陈述是错误的,所以不要让它迷惑你; 我只是把它放在这里,所以我不会破坏答案的原始上下文。
无论如何,我可以推断出累加器必须只是输出组合器组合的 1 和 0。 不过,我没有从文档中发现这一点特别明显。
我的问题
有没有办法在组合器执行之前查看输出是什么,以便我可以看到组合器组合的 1 和 0 的列表? 这将有助于调试更复杂的情况,我相信我最终会遇到这些情况。
组合器不会减少 0 和 1 的列表。 当流不是并行运行时,它不会在这种情况下使用,因此以下循环等效:
U result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
当您并行运行流时,任务会跨越到多个线程中。 例如,管道中的数据被划分为独立评估和产生结果的块。 然后使用组合器来合并这个结果。
所以你不会看到一个减少的列表,而是 2 个值,要么是身份值,要么是由任务计算出的另一个值。 例如,如果您在组合器中添加打印语句
(i1, i2) -> {System.out.println("Merging: "+i1+"-"+i2); return i1+i2;});
你可以看到这样的事情:
Merging: 0-0
Merging: 0-0
Merging: 1-0
Merging: 1-0
Merging: 1-1
这将有助于调试更复杂的情况,我相信我最终会遇到这些情况。
更一般地说,如果您想随时随地peek
管道上的数据,您可以使用peek
(或者调试器也可以提供帮助)。 因此适用于您的示例:
long countOfAWords = result.stream().map(s -> s.charAt(0) == 'A' ? 1 : 0).peek(System.out::print).mapToLong(l -> l).sum();
可以输出:
100100
[免责声明:我意识到这可能不是编写此代码的最佳方式; 只是为了练习!]。
完成任务的惯用方法是filter
流,然后简单地使用count
:
long countOfAWords = result.stream().filter(s -> s.charAt(0) == 'A').count();
希望能帮助到你! :)
查看发生了什么的一种方法是将方法引用Long::sum
替换为包含println
的 lambda。
List<String> results = Arrays.asList("A", "B", "A", "A", "C", "A", "A");
Long countOfAWords = results.stream().reduce(
0L,
(a, b) -> b.charAt(0) == 'A' ? a + 1 : a,
(a, b) -> {
System.out.println(a + " " + b);
return Long.sum(a, b);
});
在这种情况下,我们可以看到实际上并没有使用组合器。 这是因为流不是并行的。 我们真正要做的就是使用累加器将每个String
与当前的Long
结果连续组合起来; 永远不会组合两个Long
值。
如果您用parallelStream
替换stream
,您可以看到使用了组合器并查看它组合的值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.