Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why combiner function is not executed in java-8 stream reduce operation? [duplicate]

I am trying to understand how the reduce method in streams work.

Stream.of(1,2,3,4,5,6,7).reduce(new ArrayList<>(),
(List<Integer> l, Integer a) -> {l.add(a);return l;},
(List<Integer> l1, List<Integer> l2) -> {
System.out.println("l1 is" + l1 + "l2 is " + l2);
l1.addAll(l2);
return l1;
}).forEach(System.out::println);

The line System.out.println("l1 is" + l1 + "l2 is " + l2) never gets printed. I can understand what is happening in (List<Integer> l, Integer a) -> {l.add(a);return l;}
Can some one please explain why it is not printed ? The java docs say function for combining two values, which must be compatible with the accumulator function

Thanks, Amar

like image 921
Amar Dev Avatar asked Jan 04 '23 18:01

Amar Dev


2 Answers

It's only being called when the stream is parallel. In that case, the stream values are split in half (recursively), each half is reduced to a list, and then the two lists must be combined together.

Note that reduction is not supposed to mutate the values (the lists, in this case) received as argument. It's supposed to return a new value. That's what a mutable reduction (i.e. collect()) is a much better choice in this case.

like image 112
JB Nizet Avatar answered Jan 14 '23 13:01

JB Nizet


It has described in java.util.stream package summary as below:

<U> U reduce(U identity,
          BiFunction<U, ? super T, U> accumulator,
          BinaryOperator<U> combiner);

The combiner function combines two partial results to produce a new partial result. (The combiner is necessary in parallel reductions, where the input is partitioned, a partial accumulation computed for each partition, and then the partial results are combined to produce a final result.)

the "necessary" imply if your stream is empty or contains only single element in the stream, the combiner also never be called in a parallel stream.

So if you want to see "l1 is" + l1 + "l2 is " + l2 is printed, you should run it in a parallel stream, for example:

//                       v--- make the stream run in parallel   
Stream.of(1,2,3,4,5,6,7).parallel().reduce(...).forEach(System.out::println);
like image 20
holi-java Avatar answered Jan 14 '23 13:01

holi-java