/**
* Performs a <a href="package-summary.html#Reduction">reduction</a> on the
* elements of this stream, using the provided identity value and an
* <a href="package-summary.html#Associativity">associative</a>
* accumulation function, and returns the reduced value.  This is equivalent
* to:
* <pre>{@code
*    T result = identity;
*    for (T element : this stream)
*        result = accumulator.apply(result, element)
*    return result;
* }</pre>
*
* but is not constrained to execute sequentially.
*
* <p>The {@code identity} value must be an identity for the accumulator
* function. This means that for all {@code t},
* {@code accumulator.apply(identity, t)} is equal to {@code t}.
* The {@code accumulator} function must be an
* <a href="package-summary.html#Associativity">associative</a> function.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal
* operation</a>.
*
* @apiNote Sum, min, max, average, and string concatenation are all special
* cases of reduction. Summing a stream of numbers can be expressed as:
*
* <pre>{@code
*    Integer sum = duce(0, (a, b) -> a+b);
* }</pre>
*
* or:
*
* <pre>{@code
*    Integer sum = duce(0, Integer::sum);
* }</pre>
*
* <p>While this may seem a more roundabout way to perform an aggregation
* compared to simply mutating a running total in a loop, reduction
* operations parallelize more gracefully, without needing additional
* synchronization and with greatly reduced risk of data races.
*
* @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);
//⽰例
reduce(BigDecimal.ZERO, BigDecimal::add);
在 Java 8 中,duce()合并流的元素并产⽣单个值。
使⽤ for 循环的简单求和运算。
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
相当于 duce()
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
或⽅法引⽤ 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 operandjava stream
* @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. ⽅法签名
1.1 查看duce()⽅法签名:
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 = 默认值或初始值。
BinaryOperator = 函数式接⼝,取两个值并产⽣⼀个新值。(注: java Function 函数中的 BinaryOperator 接⼝⽤于执⾏ lambda 表达式并返回⼀个 T 类型的返回值)
1.2 如果缺少identity参数,则没有默认值或初始值,并且它返回 optional。Stream.java
Optional<T> reduce(BinaryOperator<T> accumulator);
2. 更多例⼦
2.1 数学运算。
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 最⼤和最⼩
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 连接字符串。
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 :)  (最好使⽤ Java 8 的 String.join)
String join = String.join("|", strings);
3. Map & Reduce
⼀个简单的 map 和 reduce ⽰例,⽤于从发票 List 中求 BigDecimal 的和。JavaReduce.java
package com.mkyong;
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().Price()))    // map,对集合中的元素进⾏操作
.reduce(BigDecimal.ZERO, BigDecimal::add);      // reduce,将上⼀步得到的结果进⾏合并得到最终的结果
System.out.println(sum);    // 49.955
System.out.println(sum.setScale(2, RoundingMode.HALF_UP));  // 49.96 使⽤setScale⽅法进⾏四舍五⼊
}
}
class Invoice {
// 发票号码
String invoiceNo;
// 价格
BigDecimal price;
// 数量
BigDecimal qty;
// getters, stters n constructor
}
输出
49.955
49.96