In Java 8, the Stream.reduce() combine elements of a stream and produces a single value.
A simple sum operation using a for loop.
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 0;
for (int i : numbers) {
sum += i;
}
System.out.println("sum : " + sum); // 55
The equivalent in Stream.reduce()
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 1st argument, init value = 0
int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a + b);
System.out.println("sum : " + sum); // 55
or method reference with Integer::sum
int sum = Arrays.stream(numbers).reduce(0, Integer::sum); // 55
Integer.java
/**
* Adds two integers together as per the + operator.
*
* @param a the first operand
* @param b the second operand
* @return the sum of {@code a} and {@code b}
* @see java.util.function.BinaryOperator
* @since 1.8
*/
public static int sum(int a, int b) {
return a + b;
}
1. Method Signature
1.1 Review the Stream.reduce() method signature:
Stream.java
T reduce(T identity, BinaryOperator<T> accumulator);
IntStream.java
int reduce(int identity, IntBinaryOperator op);
LongStream.java
long reduce(int identity, LongBinaryOperator op);
- identity = default or initial value.
- BinaryOperator = functional interface, take two values and produces a new value.
1.2 if the identity argument is missing, there is no default or initial value, and it returns an optional.
Stream.java
Optional<T> reduce(BinaryOperator<T> accumulator);
2. More Examples
2.1 Math operations.
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a + b); // 55
int sum2 = Arrays.stream(numbers).reduce(0, Integer::sum); // 55
int sum3 = Arrays.stream(numbers).reduce(0, (a, b) -> a - b); // -55
int sum4 = Arrays.stream(numbers).reduce(0, (a, b) -> a * b); // 0, initial is 0, 0 * whatever = 0
int sum5 = Arrays.stream(numbers).reduce(0, (a, b) -> a / b); // 0
2.2 Max and Min.
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int max = Arrays.stream(numbers).reduce(0, (a, b) -> a > b ? a : b); // 10
int max1 = Arrays.stream(numbers).reduce(0, Integer::max); // 10
int min = Arrays.stream(numbers).reduce(0, (a, b) -> a < b ? a : b); // 0
int min1 = Arrays.stream(numbers).reduce(0, Integer::min); // 0
2.3 Join String.
String[] strings = {"a", "b", "c", "d", "e"};
// |a|b|c|d|e , the initial | join is not what we want
String reduce = Arrays.stream(strings).reduce("", (a, b) -> a + "|" + b);
// a|b|c|d|e, filter the initial "" empty string
String reduce2 = Arrays.stream(strings).reduce("", (a, b) -> {
if (!"".equals(a)) {
return a + "|" + b;
} else {
return b;
}
});
// a|b|c|d|e , better uses the Java 8 String.join :)
String join = String.join("|", strings);
3. Map & Reduce
A simple map and reduce example to sum BigDecimal from a list of invoices.
JavaReduce.java
package com.favtuts.java8;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
public class JavaReduce {
public static void main(String[] args) {
List<Invoice> invoices = Arrays.asList(
new Invoice("A01", BigDecimal.valueOf(9.99), BigDecimal.valueOf(1)),
new Invoice("A02", BigDecimal.valueOf(19.99), BigDecimal.valueOf(1.5)),
new Invoice("A03", BigDecimal.valueOf(4.99), BigDecimal.valueOf(2))
);
BigDecimal sum = invoices.stream()
.map(x -> x.getQty().multiply(x.getPrice())) // map
.reduce(BigDecimal.ZERO, BigDecimal::add); // reduce
System.out.println(sum); // 49.955
System.out.println(sum.setScale(2, RoundingMode.HALF_UP)); // 49.96
}
}
class Invoice {
String invoiceNo;
BigDecimal price;
BigDecimal qty;
// getters, stters n constructor
}
Output
49.955
49.96
Download Source Code
$ git clone https://github.com/favtuts/java-core-tutorials-examples
$ cd java-basic/java8