Java8 stream.reduce() 有 3 个参数 - 获得透明度
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);
中间的 parameter/lambda(称为累加器)似乎能够在没有最终 'Combiner' 参数的情况下减少完整列表。事实上,Javadoc 实际上说:
The {@code accumulator} function acts as a fused mapper and
accumulator,
* which can sometimes be more efficient than separate mapping and reduction,
* such as when knowing the previously reduced value allows you to avoid
* some computation.
[Edit From Author] - 下面的说法是错误的,别误会了;我只是把它放在这里,以免破坏答案的原始上下文。
无论如何,我可以推断累加器一定只是输出组合器组合的 1 和 0。不过,我没有从文档中发现这一点特别明显。
我的问题
有没有办法在组合器执行之前查看输出结果,以便我可以看到组合器组合的 1 和 0 的列表?这将有助于调试更复杂的情况,我相信我最终会遇到这些情况。
查看发生了什么的一种方法是用包含 println
的 lambda 替换方法引用 Long::sum
。
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
,您可以看到使用了组合器并查看它组合的值。
组合器不会减少 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
This would be helpful in debugging more complex situations which I'm
sure I'll come across eventaully.
更一般地说,如果您想随时随地查看管道上的数据,可以使用 peek
(或者调试器也可以提供帮助)。所以应用于你的例子:
long countOfAWords = result.stream().map(s -> s.charAt(0) == 'A' ? 1 : 0).peek(System.out::print).mapToLong(l -> l).sum();
可以输出:
100100
[Disclaimer: I realize this is probably not the best way to write this
code; it's just for practice!].
完成任务的惯用方法是 filter
流,然后简单地使用 count
:
long countOfAWords = result.stream().filter(s -> s.charAt(0) == 'A').count();
希望对您有所帮助! :)
我编写这段代码是为了将单词列表减少到一个很长的计数,即有多少单词以 'A' 开头。我写它只是为了学习 Java 8,所以我想更好地理解它 [免责声明:我意识到这可能不是编写此代码的最佳方式;只是为了练习!].
Long countOfAWords = results.stream().reduce(
0L,
(a, b) -> b.charAt(0) == 'A' ? a + 1 : a,
Long::sum);
中间的 parameter/lambda(称为累加器)似乎能够在没有最终 'Combiner' 参数的情况下减少完整列表。事实上,Javadoc 实际上说:
The {@code accumulator} function acts as a fused mapper and accumulator, * which can sometimes be more efficient than separate mapping and reduction, * such as when knowing the previously reduced value allows you to avoid * some computation.
[Edit From Author] - 下面的说法是错误的,别误会了;我只是把它放在这里,以免破坏答案的原始上下文。
无论如何,我可以推断累加器一定只是输出组合器组合的 1 和 0。不过,我没有从文档中发现这一点特别明显。
我的问题
有没有办法在组合器执行之前查看输出结果,以便我可以看到组合器组合的 1 和 0 的列表?这将有助于调试更复杂的情况,我相信我最终会遇到这些情况。
查看发生了什么的一种方法是用包含 println
的 lambda 替换方法引用 Long::sum
。
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
,您可以看到使用了组合器并查看它组合的值。
组合器不会减少 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
This would be helpful in debugging more complex situations which I'm sure I'll come across eventaully.
更一般地说,如果您想随时随地查看管道上的数据,可以使用 peek
(或者调试器也可以提供帮助)。所以应用于你的例子:
long countOfAWords = result.stream().map(s -> s.charAt(0) == 'A' ? 1 : 0).peek(System.out::print).mapToLong(l -> l).sum();
可以输出:
100100
[Disclaimer: I realize this is probably not the best way to write this code; it's just for practice!].
完成任务的惯用方法是 filter
流,然后简单地使用 count
:
long countOfAWords = result.stream().filter(s -> s.charAt(0) == 'A').count();
希望对您有所帮助! :)