Home | | Web Programming | Reduction Operations - Java Stream API

Chapter: Java The Complete Reference : The Java Library : The Stream API

Reduction Operations - Java Stream API

Consider the min( ) and max( ) methods in the preceding example program. Both are terminal operations that return a result based on the elements in the stream.

Reduction Operations

 

Consider the min( ) and max( ) methods in the preceding example program. Both are terminal operations that return a result based on the elements in the stream. In the language of the stream API, they represent reduction operations because each reduces a stream to a single value—in this case, the minimum and maximum. The stream API refers to these as special case reductions because they perform a specific function. In addition to min( ) and max( ), other special case reductions are also available, such as count( ), which counts the number of elements in a stream. However, the stream API generalizes this concept by providing the reduce( ) method. By using reduce( ), you can return a value from a stream based on any arbitrary criteria. By definition, all reduction operations are terminal operations.

Stream defines three versions of reduce( ). The two we will use first are shown here: Optional<T> reduce(BinaryOperator<T> accumulator)

T reduce(T identityVal, BinaryOperator<T> accumulator)

 

The first form returns an object of type Optional, which contains the result. The second form returns an object of type T (which is the element type of the stream). In both forms, accumulator is a function that operates on two values and produces a result. In the second form, identityVal is a value such that an accumulator operation involving identityVal and any element of the stream yields that element, unchanged. For example, if the operation is addition, then the identity value will be 0 because 0 + x is x. For multiplication, the value will be 1, because 1 * x is x.

 

BinaryOperator is a functional interface declared in java.util.function that extends the BiFunction functional interface. BiFunction defines this abstract method:

 

R apply(T val, U val2)

 

Here, R specifies the result type, T is the type of the first operand, and U is the type of second operand. Thus, apply( ) applies a function to its two operands (val and val2) and returns the result. When BinaryOperator extends BiFunction, it specifies the same type for all the type parameters. Thus, as it relates to BinaryOperator, apply( ) looks like this:

 

T apply(T val, T val2)

 

 

Furthermore, as it relates to reduce( ), val will contain the previous result and val2 will contain the next element. In its first invocation, val will contain either the identity value or the first element, depending on which version of reduce( ) is used.

 

It is important to understand that the accumulator operation must satisfy three constraints. It must be

 

        Stateless

 

        Non-interfering

 

        Associative

 

As explained earlier, stateless means that the operation does not rely on any state information. Thus, each element is processed independently. Non-interfering means that the data source is not modified by the operation. Finally, the operation must be associative. Here, the term associative is used in its normal, arithmetic sense, which means that, given an associative operator used in a sequence of operations, it does not matter which pair of operands are processed first. For example,

 

(10 * 2) * 7

 

yields the same result as 10 * (2 * 7)

 

Associativity is of particular importance to the use of reduction operations on parallel streams, discussed in the next section.

 

The following program demonstrates the versions of reduce( ) just described:

 

// Demonstrate the reduce() method.

 

import java.util.*;

 

import java.util.stream.*;

 

class StreamDemo2 {

 

public static void main(String[] args) {

 

// Create a list of Integer values.

 ArrayList<Integer> myList = new ArrayList<>( );

 

myList.add(7);

 

myList.add(18);

 

myList.add(10);

 

myList.add(24);

 

myList.add(17);

 

myList.add(5);

 

     //Two ways to obtain the integer product of the elements

 

     //in myList by use of reduce().

 

Optional<Integer> productObj = myList.stream().reduce((a,b) -> a*b); if(productObj.isPresent())

 

System.out.println("Product as Optional: " + productObj.get());

 

int product = myList.stream().reduce(1, (a,b) -> a*b); System.out.println("Product as int: " + product);

 

}

 

}

 

As the output here shows, both uses of reduce( ) produce the same result:

 

Product as Optional: 2570400

 

Product as int: 2570400

 

In the program, the first version of reduce( ) uses the lambda expression to produce a product of two values. In this case, because the stream contains Integer values, the Integer objects are automatically unboxed for the multiplication and reboxed to return the result. The two values represent the current value of the running result and the next element in the stream. The final result is returned in an object of type Optional. The value is obtained by calling get( ) on the returned object.

 

In the second version, the identity value is explicitly specified, which for multiplication is 1. Notice that the result is returned as an object of the element type, which is Integer in this case.

 

Although simple reduction operations such as multiplication are useful for examples, reductions are not limited in this regard. For example, assuming the preceding program, the following obtains the product of only the even values:

 

int evenProduct = myList.stream().reduce(1, (a,b) -> { if(b%2 == 0) return a*b; else return a;

 

});

 

Pay special attention to the lambda expression. If b is even, then a * b is returned. Otherwise, a is returned. This works because a holds the current result and b holds the next element, as explained earlier.

 

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail
Java The Complete Reference : The Java Library : The Stream API : Reduction Operations - Java Stream API |


Privacy Policy, Terms and Conditions, DMCA Policy and Compliant

Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.