[五]java函数式编程归约reduce概念原理 stream reduce方法详解 reduce三个参数的reduce方法如何使用

reduce-归约

看下词典翻译:

好的命名是自解释的

reduce的方法取得就是其中归纳的含义

java8 流相关的操作中,我们把它理解 "累加器",之所以加引号是因为他并不仅仅是加法

他的运算可以是一个Lambda 表达式

所以更准确的说 reduce 是一个迭代运算器

Stream包的文档中其实已经说的很明白了

但是就是因为不是很理解所以看的云里雾里

其中说到:

一个reduce操作(也称为折叠)接受一系列的输入元素,并通过重复应用操作将它们组合成一个简单的结果

参照reduce方法文档给出的示例

T result = identity;

for (T element : this stream)

result = accumulator.apply(result, element)

return result;

累计运算的概念

以下面的这个方法为例解析

BinaryOperator 是BiFunction 的三参数特殊化形式,两个入参和返回结果都是类型T

计算1,2,3,4,5 的和,并且初始值为3   也就是计算3+1+2+3+4+5

1.使用Stream 两个参数的reduce方法进行归约运算

2.使用for循环迭代调用BinaryOperator 的apply进行运算

其实两种方式背后的思维方式是一样的

那就是   

结果重新作为一个参数,不断地参与到运算之中,直到最后结束

理解reduce的含义重点就在于理解"累   加   器" 的概念

只要能够理解了累计运算的概念

就可以完全理解Stream 中reduce方法

他就是一个不断累计运算的过程

Stream的一个参数和两个参数的方法的基本逻辑都是如此 差别仅仅在于一个参数的是result  R = T1 ,然后再继续与剩下的元素参与运算

三个参数的reduce

    <U> U reduce(U identity,

                 BiFunction<U, ? super T, U> accumulator,

                 BinaryOperator<U> combiner);

它的形式类似于

与两个参数的reduce不同的地方在于类型 双参数的返回类型为T  Stream类型为T 三参数的返回类型为U  Stream类型为T   有了更大的发挥空间  T可能为U 也可能不是U

很显然,三参数的reduce 方法的思维方式同双参数的并无二致

所以问题来了,那还要第三个参数做什么?

其实第三个参数用于在并行计算下 合并各个线程的计算结果

并行流运行时:内部使用了fork-join框架

多线程时,多个线程同时参与运算

多个线程执行任务,必然会产生多个结果

那么如何将他们进行正确的合并

这就是第三个参数的作用

大致处理流程

从流程上看的 结果R是一直参与运算的!!

我们之前也有一个例子

两种情况下的结果是不一样的!!!!

结果不同  是因为  ((((5+1)+2)+3)+4)+5   和   (5+1)+ (5+2)+ (5+3)+ (5+4)+ (5+5)  运算结果不相同 

那么这个方法不是有问题么?

其实不然,有问题的是我们的写法

文档中进行了明确的说明要求

翻译下:

第一点:identity 的值对于合并运算combiner来说必须是一个恒等式,也就是说对于任意的u,  combiner(identity,u)  和u是相同的

这句话看起来怪怪的,对于任意的u 经过合并运算 竟然还是u,那还要这个干嘛??

从我们上面的并行处理流程可以看得出来,这个result 的初始identity 对于每一个分支都是参与运算的!

这也是为什么要求:

任意的u,  combiner(identity,u)  和u是相同的

的原因

我们之所以会错,就是因为没有达到要求  

我们的combiner为   (a,b)->a+b;

那么如果分为两个分支进行运算,我们的初始值identity就参与了两次运算  也就是说多加了两个identity的值!!

怎么样才能保证u = combiner(identity,u)  

除非identity=0  这才是对于  (a,b)->a+b  来说能够保障u = combiner(identity,u)    

否则,你就不要用(a,b)->a+b  这个combiner

我们把Identity换成0之后

结果就不再有问题了

第二点

combiner 必须和accumulator要兼容

对于任意的u 和 t

这到底是什么意思呢?

场景 假设说4个元素 1,2,3,4  需要运算 此时假设已经 1,2,3 三组数据已经运算结束,马上要同第四组运算  如果是并行,我们假定1,2,3 在一个分支   4单独在另一分支

并行时 U为已经计算好的1,2,3后的结果     接下来要与另一组的4 合并 T4则是identity与T参与运算 上面的图就是 combiner.apply(u, accumulator.apply(identity, t))

非并行运算 u 直接与下一个元素进行结合运算

显然这只是并行和非并行两种不同的处理运算方式,他们应该是相同的

也就是

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我就是马云飞

设计模式二十四章经之工厂模式

1252
来自专栏Java学习网

Java中有关Null的9问题

Java中有关Null的9问题 对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NPE)的骚扰。连Java的发明者都承认...

2235
来自专栏java一日一条

Java中有关Null的9件事

对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NPE)的骚扰。连Java的发明者都承认这是他的一项巨大失误。Java为什么要保留nul...

652
来自专栏带你撸出一手好代码

Java元组的使用

元组在计算机领域有着特殊的意义,这个名字听起来似乎有些陌生, 平时在写代码也基本没什么应用场景, 然而, 出人意料的是, 元组跟程序设计密切相关, 可能有的同学...

4848
来自专栏java一日一条

Java中有关Null的9件事

对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NPE)的骚扰。连Java的发明者都承认这是他的一项巨大失误。Java为 什么要保留nu...

932
来自专栏逸鹏说道

我为NET狂面试题-基础篇-答案

面向过程: 答案:图片只贴核心代码,完整代码请打开解决项目查看 (答案不唯一,官方答案只供参考,若有错误欢迎提出~) 99乘法表 https://githu...

35613
来自专栏工科狗和生物喵

【计算机本科补全计划】C++ Primer:指针和const限定符

正文之前 今天下午看了一下午的计算机组成与设计,结果好死不死的看到了设计部分--处理器的设计。天哪,我现在还只是一个准备给人装一台电脑做实验田的家伙,连用都不咋...

2794
来自专栏喵了个咪的博客空间

zephir-(10)内置函数

#zephir-内置函数# ? ##前言## 先在这里感谢各位zephir开源技术提供者 嗨!大家好呀,今天要和大家一同学习zephir的内置函数,学过PHP的...

3658
来自专栏Python小屋

Python标准库collections中与字典有关的类

Python标准库中提供了很多扩展功能,大幅度提高了开发效率。这里主要介绍OrderedDict类、defaultdict类和Counter类。 (1)Orde...

2826
来自专栏大数据和云计算技术

由快速排序到分治思想

算法是基础,小蓝同学准备些总结一系列算法分享给大家,这是第一篇《由快速排序到分治思想》,非常赞!希望对大家有帮助,大家会喜欢! 快速排序是一种基于分治思想...

3496

扫码关注云+社区

领取腾讯云代金券