Inspecting Reduce Function

Introduction

The article explains about the important Stream function ‘reduce’, In the Stream API there are various ‘terminal’ operations, some of them are.

  1. allMatch
  2. anyMatch
  3. collect
  4. count
  5. max
  6. min
  7. forEach
  8. reduce

We will understand ‘reduce’. The ‘reduce’ is a reduction function, reduction means on applying the ‘reduce’ function on the Stream elements a single result is produced.

Let’s understand ‘reduce’ in depth by a basic example and steps of its execution. Consider a List of Integers and using reduce function we will get the Sum of all the elements of Stream.

List<Integer> list = List.of(1,2,3,4,5);
int sum = list.stream()
 .reduce((x, y) -> x + y)
 .get(); //returns 15

The way function works internally is,

Step 1

First, 1 is added 2

Step 2

The result of 1st step which is 3 added to the next element of Stream which is 3

Step 3

The result of the 2nd step is 6, and the next element of Stream is 4.

Step 4

The result of the 3rd step is 10 and the next element of Stream is 5, resulting in 15.

Function Syntax

There are 2 variations of the 'reduce' function.

 * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
 * <a href="package-summary.html#NonInterference">non-interfering</a>,
 * <a href="package-summary.html#Statelessness">stateless</a>
 * function for combining two values
 * @return an {@link Optional} describing the result of the reduction
 * @throws NullPointerException if the result of the reduction is null
 * @see #reduce(Object, BinaryOperator)
 * @see #min(Comparator)
 * @see #max(Comparator)
 */
 Optional<T> reduce(BinaryOperator<T> accumulator);

Implementation of this function we have already seen in our List addition example, the point to note here is that the variation of this function doesn’t take any seed value and it returns Optional monad, that’s why we did .get().intValue() to retrieve the value from the Monad.

Another variation, with a seed value

 * @param identity the identity value for the accumulating function
 * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
 * <a href="package-summary.html#NonInterference">non-interfering</a>,
 * <a href="package-summary.html#Statelessness">stateless</a>
 * function for combining two values
 * @return the result of the reduction
 */
 T reduce(T identity, BinaryOperator<T> accumulator);

The purpose of the initial value is if the stream is not empty the initial value will be applied to the first element of the Stream.

List<Integer> list = List.of(1, 2, 3, 4, 5);
sum = list.stream()
 .reduce(1, (x, y) -> x + y); // returns 16

The result of the above calculation is 16, as 1 is our seed value. If the Stream is empty, the initial value is returned.

List<Integer> list = new ArrayList<>();
sum = list2.stream()
 .reduce(1, (x, y) -> x + y); //returns 1 as it's our initial value

Since our Stream is empty, 1 is returned which is our seed value. That’s why the 2nd variation of the ‘reduce’ function doesn’t return Optional because it is guaranteed that result of this function is never going to be null, so no reason to return Optional, it’s perfectly made sense.

More Examples using reduce function

1. Find the String with maximum length from List of Strings using the ‘reduce’ function

List<String> names= List.of("Sameer Shukla", "David", "Mick");
String result = names.stream()
 .reduce("", (s1, s2) -> (s1.length() > s2.length()) ? s1 : s2);
//returns Sameer Shukla

2. Find maximum element from the List of Integers

List<Integer> list = List.of(1, 2, 3, 4, 5);
int max = list.stream()
 .reduce(Integer :: max)
 .get(); // returns 15

3. Concatenate the elements of the names list

String concat = names.stream()
 .reduce((s1, s2) -> s1 + "," + s2)
 .get(); // Sameer Shukla,David,Mick

I hope you find the article useful, I will try to cover a lot more stream functions in upcoming articles. Thank you for reading