当前位置: 首页 > 工具软件 > Reduce > 使用案例 >

Stream.reduce()合并流 例BigDecimal 的add求和

督灿
2023-12-01

先看源码:

/**
 * 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 = integers.reduce(0, (a, b) -> a+b);
 * }</pre>
 *
 * or:
 *
 * <pre>{@code
 *     Integer sum = integers.reduce(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 中,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.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().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 使用setScale方法进行四舍五入
 
    }
 
}
 
class Invoice {
 
    // 发票号码
    String invoiceNo;
    // 价格
    BigDecimal price;
    // 数量
    BigDecimal qty;
 
    // getters, stters n constructor
}

输出

49.955

49.96

参考:https://blog.csdn.net/u014748504/article/details/111868912 

 类似资料: