Java8-stream使用-reduce

reduce:原文减少,

这里的意思是:根据一定的规则将Stream中的元素进行计算后返回一个唯一的值

举例:

元素求和:

以前我们是这样算的:

Int sum = 0;

for (int x : numbers)

Sum += x;

通过反复使用加法,你把一个数字列表归约成了一个数字;

要是还能把所有的数字相乘,而不必去复制粘贴这段代码,岂不是很好?这正是reduce操作的用武之地,它对这种重复应用的模式做了抽象。你可以像下面这样对流中所有的元素求和:

Int sum = numbers.stream().reduce(0, (a,b) -> a+b);

reduce 接受2个参数:

  1. 一个初始值,这里是0:
  2. 一个BinaryOperator<T>来将两个元素结合起来产生一个新值,这里我们用的是lambda(a, b) -> a+b。

也很容易把所有的元素相乘,只需要将另一个Lambda:(a, b) -> a*b 传递给reduce操作就可以了:

int product = numbers.stream().reduce(1, (a,b) -> a*b);

下图展示了reduce操作时如何作用于一个流的:Lambda反复结合每个元素,直到流被归约成一个值。

让我们深入研究一下reduce操作时如何对一个数字流求和的。

首先,0作为Lambda(a)的第一个参数,从流中获取4作为第二个参数(b)。

0+4得到4,它成了新的累积值。

然后再用累积值和流中下一个元素5调用Lambda,产生新的累积值9。

接下来,再用累积值和下一个元素3调用Lambda,得到12。

最后,用12和流中最后一个元素9调用Lambda,得到最终结果21。

你可以使用方法引用让着段代码更简洁。在java8中,Integer类现在有了一个静态的sum方法来对两个数求和,这恰好时我们想要的,用不着反复用Lambda写同一段代码了:

int sum = numbers.stream().reduce(Integer::sum);

无初始值

reduce 还有一个重载的变体,它不接受初始值,但是会返回一个Optional对象:

Optional<Integer> sum = numbers.stream().reduce((a,b) -> a+b);

为什么它返回一个Optional<Integer>呢?考虑流中没有任何元素的情况。

reduce操作无法返回其和,因为它没有初始值。这就是为什么结果被包裹在一个Optional对象里,以表明和可能不存在。现在看看reduce还能做什么。

这里复制了别人的几个例子,非常好用:

数学运算:

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

最大和最小:

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

连接字符串:

  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);

map 和 reduce:

一个简单的 map 和 reduce 示例,用于从发票 List 中求 BigDecimal 的和。

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

统计坐标点的距离(x,y):

计算某个点到某一批点的最近距离(两点坐标的距离):

public class Position{
    private float x;

    private float y;
}


private List<Position> batchPosition;
private Position position;
 
Float distance = batchPosition.stream().map(v -> Math.abs(v.getX() - position.getX()) + Math.abs(v.getY() - position.getY())).reduce(Float::min).orElse(Float.MAX_VALUE);

引用:

https://blog.csdn.net/weixin_44368487/article/details/107658522

https://www.pianshen.com/article/3741873730/

https://www.jianshu.com/p/08e7f38f0a1b

https://www.cnblogs.com/gaohanghang/p/12390233.html

猜你喜欢

转载自blog.csdn.net/u010953880/article/details/116518540