Java8 stream.reduce() with 3 parameters - getting transparency

与世无争的帅哥 提交于 2019-11-28 11:20:07

The combiner does not reduce a list of 0's and 1's. When the stream is not run in parallel it's not used in this case so that the following loop is equivalent:

U result = identity;
for (T element : this stream)
    result = accumulator.apply(result, element)
return result;

When you run the stream in parallel, the task is spanned into multiple threads. So for example the data in the pipeline is partitioned into chunks that evaluate and produce a result independently. Then the combiner is used to merge this results.

So you won't see a list that is reduced, but rather 2 values either the identity value or with another value computed by a task that are summed. For example if you add a print statement in the combiner

(i1, i2) -> {System.out.println("Merging: "+i1+"-"+i2); return i1+i2;}); 

you could see something like this:

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.

More generally if you want to see the data on the pipeline on the go you can use peek (or the debugger could also help). So applied to your example:

long countOfAWords = result.stream().map(s -> s.charAt(0) == 'A' ? 1 : 0).peek(System.out::print).mapToLong(l -> l).sum();

which can output:

100100

[Disclaimer: I realize this is probably not the best way to write this code; it's just for practice!].

The idiomatic way to achieve your task would be to filter the stream and then simply use count:

long countOfAWords = result.stream().filter(s -> s.charAt(0) == 'A').count();

Hope it helps! :)

One way to see what's going on is to replace the method reference Long::sum by a lambda that includes a println.

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);
        });

In this case, we can see that the combiner is not actually used. This is because the stream is not parallel. All we are really doing is using the accumulator to successively combine each String with the current Long result; no two Long values are ever combined.

If you replace stream by parallelStream you can see that the combiner is used and look at the values it combines.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!