一文搞懂 java8 reduce操作

什么是 reduce

Java8 中有两大最为重要的改变,其一是 Lambda 表达式,另一个就是 Stream API 了。

Stream 是 Java8 中处理集合的关键抽象概念,它将数据源流化后,可以执行非常复杂的查找、过滤和映射数据、排序、切片、聚合统计等操作。操作之后会产生一个新的流,而数据源则不会发生改变。

在使用 Stream 操作的过程中,往往有三个步骤,

1. 创建 Stream

从一个数据源(集合,数组)中,新建一个 Stream 流。

2. 中间操作

一个中间操作链,对 Stream 流的数据进行处理。比如查找、过滤、映射转换等。

3. 终止操作

一个终止操作,执行中间操作链,并产生结果。常用的终止操作有 forearch、collect、match、count、min、max、reduce 等。

其中本文主要讲解的 reduct 操作就属于是 Stream 流操作中的终止操作。


reduce 操作是一种通用的归约操作,它可以实现从 Stream 中生成一个值,其生成的值不是随意的,而是根据指定的计算模型。

比如终止操作中提到 count、min 和 max 方法,因为常用而被纳入标准库中。事实上这些方法都是一种 reduce 操作。

本文大纲如下,

reduce 操作三要素

为了方便大家理解 reduce (规约)操作,先给大家演示一下 reduce 操作的相关代码示例,

 

java

复制代码

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); int result = numbers .stream() .reduce(0, (subtotal, element) -> subtotal + element); assertThat(result).isEqualTo(21);

可以看到,我们的 reduce 操作接受了三个参数,返回了一个 int 基本类型。

在 Stream API 中,提供了三个 reduct 操作方法,根据参数不同进行区分。

对应上方代码示例,也就是使用了接受两个参数的 reduce 方法,但其实接受两个参数的 reduce 方法的代码逻辑是和接受三个参数的 reduce 方法是一致的。通过上方截图可以看出。

所以这里,我就直接给大家介绍下 reduce 操作的三个参数分别有什么作用即可。

identiy 参数

identiy(初始值)是 reduce 操作的初始值,也就是当元素集合为空时的默认结果。对应上方代码示例,也就是说 reduce 操作的初始值是 0。

accumulator 参数

accumulator(累加器)是一个函数,它接受两个参数,reduce 操作的部分元素和元素集合中的下一个元素。它返回一个新的部分元素。在这个例子中,累加器是一个 lambda 表达式,它将集合中两个整数相加并返回一个整数:(a, b) -> a + b。

combiner 参数

combiner(组合器)是一个函数,它用于在 reduce 操作被并行化或者当累加器的参数类型和实现类型不匹配时,将 reduce 操作的部分结果进行组合。在上面代码示例中,我们不需要使用组合器,因为上面我们的 reduce 操作不需要并行,而且累加器的参数类型和实现类型都是 Integer。


为了方便大家理解 reduce 操作的内部逻辑,我给大家绘制了上面代码示例的执行示意图,如下,

如何使用 reduce 操作

为了更好地理解初始值,累加器和组合器的功能,让我们看一些基本的例子。

使用 reduce 查询整数集合的最小值

 

java

复制代码

// 创建一个整数集合 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); // 找出集合中的最小值 Integer min = numbers.stream().reduce((integer, integer2) -> { if (integer < integer2) { return integer; } else { return integer2; } }).get(); // 输出结果 System.out.println(min); // 1

在这个例子中,我们使用了一个参数的 reduce 操作,它接受一个累加器函数。累加器函数会返回集合两个元素中,较小的元素。

最终我们就可以找出集合中最小值 1。

使用 reduce 操作拼接字符串列表

我们可以对一个字符串列表使用 reduce 操作,将它们拼接成一个单一的字符串:

 

java

复制代码

// 创建一个字符串列表 List<String> letters = Arrays.asList ("a", "b", "c", "d", "e"); // 使用 reduce 操作拼接字符串列表 String result = letters .stream () .reduce ("", (partialString, element) -> partialString + element); // 输出结果 System.out.println (result); // abcde

在这个例子中,我们将初始值设为 "",累加器函数设为 (a, b) -> a + b,它表示将两个字符串拼接起来。

我们可以看到,reduce 操作将累加器函数反复应用到列表中的每个元素上,得到最终的结果 abcde。

使用并行流计算整数列表的总和

 

java

复制代码

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5,6); // 使用并行流和 reduce() 方法计算整数列表的总和 int result = numbers.parallelStream() .reduce(0, (a, b) -> a + b, Integer::sum); // 输出结果 System.out.println(result); // 21

在这个例子中,我们使用 parallelStream() 方法将列表转换为并行流,再使用 reduce() 方法对整数列表进行 reduce 操作,并使用 Integer::sum 作为合并函数 combiner,将并行计算的结果合并。

使用并行流的好处能够充分利用多核 CPU 的优势,使用多线程加快对集合数据的处理速度。

不过并行流也不是任何时候都可以使用的,并行流执行过程中实际按照多线程执行,多线程编程有的问题,并行流都有。

比如多线程的线程安全,执行顺序等问题,并行流都是有的。这一点需要大家注意。

最后聊两句

本文介绍了 Java8 Stream 流中,reduce 操作的相关概念和接收参数,包含初始值,累加器和组合器,最后介绍了 reduce 操作如何使用,希望大家喜欢。

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CAN(Controller Area Network,控制器局域网)总线协议是一种广泛应用于工业自动化、汽车电子等领域的串行通讯协议。其帧格式如下: <img src="https://img-blog.csdnimg.cn/20200925125252655.png" width="400"> CAN总线协议的帧分为标准帧和扩展帧两种,其中标准帧包含11位标识符,扩展帧包含29位标识符。在CAN总线上,所有节点都可以同时发送和接收数据,因此需要在帧中包含发送方和接收方的信息。 帧格式的具体解释如下: 1. 帧起始符(SOF):一个固定的位模式,表示帧的起始。 2. 报文控制(CTRL):包含几个控制位,如IDE、RTR等。其中IDE表示标识符的类型,0表示标准帧,1表示扩展帧;RTR表示远程请求帧,0表示数据帧,1表示远程请求帧。 3. 标识符(ID):11位或29位的标识符,用于区分不同的CAN消息。 4. 控制域(CTL):包含几个控制位,如DLC、EDL等。其中DLC表示数据长度,即数据域的字节数;EDL表示数据长度是否扩展,0表示标准数据帧,1表示扩展数据帧。 5. 数据域(DATA):0~8字节的数据。 6. CRC:用于校验数据是否正确。 7. 确认位(ACK):由接收方发送的确认信息,表示数据是否正确接收。 8. 结束符(EOF):一个固定的位模式,表示帧的结束。 以上就是CAN总线协议的帧格式。在实际应用中,节点之间通过CAN总线进行数据交换,通过解析帧中的各个字段,可以判断消息的发送方、接收方、数据内容等信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值