我编写这段代码是为了将单词列表缩减为以'A‘开头的单词数量的长计数。我编写它只是为了学习Java 8,所以我想更好地理解它:我意识到这可能不是编写这段代码的最佳方式;它只是为了实践!
Long countOfAWords = results.stream().reduce(
0L,
(a, b) -> b.charAt(0) == 'A' ? a + 1 : a,
Long::sum);
中间参数/lambda(称为累加器)似乎能够在没有最后的'Combiner‘参数的情况下减少完整的列表。事实上,Javadoc实际上说:
{@code累加器}函数充当一个融合映射器和累加器,*它有时比单独的映射和还原更有效,例如当知道以前的约简值时,可以避免*某些计算。
作者的编辑-下面的陈述是错误的,所以不要让它迷惑你;我只是把它保存在这里,这样我就不会破坏原来答案的上下文。
无论如何,我可以推断,累加器必须输出组合器组合的1和0。不过,从文档中我并没有发现这一点特别明显。
我的问题
有没有办法在组合器执行之前查看输出,这样我就可以看到组合器组合的1和0的列表了吗?这将有助于调试更复杂的情况,我相信我最终会遇到这种情况。
发布于 2015-05-03 16:15:19
组合器不会减少0和1的列表。当流不是并行运行时,在这种情况下不使用它,因此下面的循环是等价的:
U result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
当您并行运行流时,任务会跨成多个线程。因此,例如,管道中的数据被划分为独立评估和生成结果的块。然后,组合器用于合并这个结果。
因此,您将不会看到减少的列表,而是两个值--标识值或由任务之和计算的另一个值。例如,如果您在组合器中添加了一个print语句
(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
这将有助于调试更复杂的情况,我肯定会遇到这样的情况。
更普遍的情况是,如果您想查看go管道上的数据,可以使用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();
希望能有所帮助!)
发布于 2015-05-03 16:14:53
查看正在发生的事情的一种方法是将方法引用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
值被组合。
如果将stream
替换为parallelStream
,则可以看到使用了组合器,并查看了它组合的值。
https://stackoverflow.com/questions/30015971
复制相似问题