Java 8 Stream.reduce()详解

作者 | 2020年4月10日

在Java8中,Stream.reduce()方法可以把多个元素组合为一个元素。

我们先来看一个使用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

再来看一下如何使用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

或者使用方法引用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. 方法签名

1.1 下面给出了一些Stream.reduce()的方法签名,可以看出,在不同的Stream实现中具有不同的签名。

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 = 函数式接口,接受两个参数返回一个新值

1.2 如果没有传递identity参数,则意味着没有初始值,则可能出现值为空的清空(如果Stream中没有元素),所有Stream.reduce()这时返回一个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, 初始值是0, 0 * 任何值 = 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 , 初始值是空字符串
  String reduce = Arrays.stream(strings).reduce("", (a, b) -> a + "|" + b);

  // a|b|c|d|e, 过滤掉空字符串
  String reduce2 = Arrays.stream(strings).reduce("", (a, b) -> {
      if (!"".equals(a)) {
          return a + "|" + b;
      } else {
          return b;
      }
  });

  // 更好的方法是使用Java 8的String.join
  String join = String.join("|", strings);

3. Map与Reduce

这是一个简单的Map与Reduc例子,它使用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().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
}

输出

49.955
49.96

发表评论

电子邮件地址不会被公开。 必填项已用*标注