4

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

holi-java
  • 29,655
  • 7
  • 72
  • 83
Amar Dev
  • 1,360
  • 2
  • 18
  • 38

2 Answers2

6

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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I was trying an example tat has been listed in Java 8 in action and it mentions the note that you have mentioned as well. – Amar Dev Jul 08 '17 at 12:40
3

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);
holi-java
  • 29,655
  • 7
  • 72
  • 83