JavaFunctional streams

Reduction methods

The reduce operation

The reduce is a terminal operation which combines elements of a stream into a single value. The result can be a value of a primitive type or even a complex object. The main argument of the reduce operation is a two-arguments function for accumulating the result.

It combines elements of the stream into a single object (aggregation N to 1)

But how does it work?

Let's assume we have a list of numbers 1, 2, ..., 7. Let's summarize the numbers using reduce:

int sum = numbers.stream().reduce(0, (acc, elem) -> acc + elem);

The first argument of the reduce method is a neutral element (also known as an identity or a seed). In this case, it is 0 (0 + elem = elem). The second argument is a sum function. The sum function accepts two parameters: acc is an accumulated value and elem is a next element in the stream.

These are our calculations: (((((((0 + 1) + 2) + 3) + 4) + 5) + 6) + 7).

We can see it if just add println into the lambda:

(acc, elem) -> { 
    System.out.println("acc = " + acc + ", " + "elem = " + elem);
    return acc + elem;
}

The output:

acc = 0, elem = 1
acc = 1, elem = 2
acc = 3, elem = 3
acc = 6, elem = 4
acc = 10, elem = 5
acc = 15, elem = 6
acc = 21, elem = 7

After computing 21 + 7 = 28.

Note: accumulating is one of the main principles of a reduction.

Other reduce-like operations

The reduce operation can be used to implement such operations as a sum, finding min (or max) and others. But the Stream API already has these operations.

Here is an example: summing elements of an IntStream (sum aggregation):

long sum = IntStream.of(3, 5, 6, 7).sum();

The sum is 21.

Here is another example - finding a minimum of a stream of positive numbers:

long min = IntStream.of(11, 12, 7, 3, 10, 22).min().orElse(Integer.MAX_VALUE);

This operation returns 3.

The invoking of orElse(Integer.MAX_VALUE) allows you to get the default result (Integer.MAX_VALUE) if the stream is empty.

The same code using the reduce method:

long min = IntStream.of(11, 12, 7, 3, 10, 22).reduce(Integer.MAX_VALUE, (x, y) -> x < y ? x : y);

The first argument (Integer.MAX_VALUE) will be used as a default value and for the first comparison, the second argument is an accumulating function to keep the minimum value.

Also, the Stream API has other methods for accumulating values. See JavaDoc for details.

How did you like the theory?
Report a typo