HOWTO · Java

The Stream Reduce Operation in Java

This article introduces the reduce operation of stream in Java.

On this page

reduce() combines stream elements into a result, such as a sum or an extreme value. It is a terminal operation: after it runs, that stream cannot be used for another operation. Unlike collect(), which builds a mutable result container, the two-argument reduce() overload returns the value produced by its reduction function.

What reduction does in a Java stream

A reduction repeatedly combines values until it has one result. For a stream of integers, that result might be their total, smallest value, or largest value. A reduction does not return a single stream. Java also has specialized terminal operations, such as sum(), min(), and max(), for common numeric tasks.

How the two-argument reduce() works

The two-argument overload has the form reduce(identity, accumulator). The identity is the starting result and must leave any value unchanged when passed to the accumulator. The accumulator takes the current partial result and the next stream element, then returns an updated result. With an identity supplied, reducing a stream with no elements returns that identity.

The accumulator should be stateless, non-interfering, and associative: grouping the same values in different pairs must produce the same result. Associativity matters especially for parallel streams, where Java may combine partial results in a different order. A subtraction accumulator, for example, is not associative and is unsuitable for a parallel reduction. The result type and accumulator types must also match the overload being used.

Sum a stream with reduce()

Run this example:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {45, 56, 87, 323, 47, 20, 658, 985, 78, 123};
        int sum = Arrays.stream(numbers).reduce(0, (subtotal, number) -> subtotal + number);
        System.out.println("sum: " + sum);
    }
}

Here, 0 is the identity and the lambda adds each number to the running subtotal. You can use the method reference Integer::sum in place of (subtotal, number) -> subtotal + number; it expresses the same addition more compactly. For an integer stream with no elements, this identity-based sum is zero. For int values, arithmetic follows Java’s integer overflow rules.

Find minimum and maximum with reduce()

For a minimum, Integer.MAX_VALUE acts as an identity for Math.min; for a maximum, Integer.MIN_VALUE acts as an identity for Math.max. These are sentinel values chosen so that a real stream value replaces them during the reduction. The following complete example computes both results:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {45, 56, 87, 323, 47, 20, 658, 985, 78, 123};
        int min = Arrays.stream(numbers).reduce(Integer.MAX_VALUE, Math::min);
        int max = Arrays.stream(numbers).reduce(Integer.MIN_VALUE, Math::max);
        System.out.println("min: " + min);
        System.out.println("max: " + max);
    }
}

If the stream has no elements, these identity-based reductions return Integer.MAX_VALUE for the minimum and Integer.MIN_VALUE for the maximum. Those sentinel results are not actual extrema from the input. If the caller needs to distinguish “no value” from a real result, use the min() or max() operation, whose result for an IntStream is an OptionalInt.

When should you use reduce()?

Use reduce() when you need a general combination rule with a valid identity and associative accumulator. For an ordinary integer total, IntStream.sum() states the intent more clearly; min() and max() also make the desired operation explicit and represent the absence of a value with OptionalInt. Choose the specialized operation when it expresses the task. Use reduce() when the combining operation itself is the point, and ensure its identity and associativity rules hold before using a parallel stream.