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 直接与下一个元素进行结合运算

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

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

  1. Java并发编程(06):Lock机制下API用法详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Lock体系结构 1.基础接口简介 Lock加锁相关结构中涉及两个使用广泛的基础API:ReentrantLock类和Condition接 ...

  2. Java中JNI的使用详解第三篇:JNIEnv类型中方法的使用

    转自: http://blog.csdn.net/jiangwei0910410003/article/details/17466369 上一篇说道JNIEnv中的方法的用法,这一篇我们就来通过例子来 ...

  3. Java并发编程的艺术笔记(九)——FutureTask详解

    FutureTask是一种可以取消的异步的计算任务.它的计算是通过Callable实现的,多用于耗时的计算. 一.FutureTask的三种状态 二.get()和cancel()执行示意 三.使用 一 ...

  4. java网络编程学习笔记(二):socket详解

    1.Socket有多种构造方法,大多数构造方法在构造的时候就指定了连接的主机和端口号.当客户端的构造方法与服务器连接的时候,可能需要等待一段时间,因为需要建立连接.默认情况下,Socket的构造方法会 ...

  5. Java并发编程的艺术笔记(十)——Semaphore详解

    作用:控制同时访问某个特定资源的线程数量,用在流量控制.

  6. 《深入理解Java函数式编程》系列文章

    Introduction 本系列文将帮助你理解Java函数式编程的用法.原理. 本文受启发于JavaOne 2016关于Lambda表达式的相关主题演讲Lambdas and Functional P ...

  7. Java函数式编程原理以及应用

    一. 函数式编程 Java8所有的新特性基本基于函数式编程的思想,函数式编程的带来,给Java注入了新鲜的活力. 下面来近距离观察一下函数式编程的几个特点: 函数可以作为变量.参数.返回值和数据类型. ...

  8. paip.提升效率---filter map reduce 的java 函数式编程实现

    #paip.提升效率---filter map reduce 的java 函数式编程实现 ======================================================= ...

  9. 20145208 实验五 Java网络编程

    20145208 实验五 Java网络编程 实验内容 1.用书上的TCP代码,实现服务器与客户端. 2.客户端与服务器连接 3.客户端中输入明文,利用DES算法加密,DES的秘钥用RSA公钥密码中服务 ...

随机推荐

  1. 【转】Android studio安装与配置

    Android studio安装与配置 1.首先下载Android studio安装包,可以从http://www.android-studio.org/下载最新版本,这里采用3.0版本进行演示,对应 ...

  2. Linux指令集

    最近在学习Linux虚拟机,下面是我在学习虚拟机的过程中使用过的一些指令,及其作用. pwd-> 列出当前目录路径 ls-> 列出当前目录列表 cd-> 改变目录 mkdir-> ...

  3. Spring boot 处理 error 的套路

    Spring boot 处理 error 的基本流程: Controller -> 发生错误 -> BasicErrorController -> 根据 @RequestMappin ...

  4. Spring SpringMVC SpringBoot SpringCloud概念、关系及区别

    一.正面解读: Spring主要是基于IOC反转Beans管理Bean类,主要依存于SSH框架(Struts+Spring+Hibernate)这个MVC框架,所以定位很明确,Struts主要负责表示 ...

  5. Windows下Flume的安装

    flume(日志收集系统) Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flum ...

  6. css中文字体解决方案

    html { font-family: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica, &qu ...

  7. 什么是 ajax?----异步 javascript 和 xml

    GET 用于请求服务器数据 POST 用于上传数据到服务器,或者修改服务器数据 ajax 异步通信,实现页面的局部刷新,按需获取数据,节约带宽,带来更好的用户体验 客户端与服务器在不必刷新浏览器的情况 ...

  8. 树莓派3B+上运行.Net Core项目

    最近买了个树莓派3B+,准备把自己写的一个.Net Core爬虫挂在上面跑 买之前没有想到树莓派因为是今年新出的,导致驱动以及系统啥的都不是很完善,导致走了很多弯路,早知道买树莓派3就不用那么多折腾了 ...

  9. IntelliJ Idea 2017 免费激活方法

    1. 到网站 http://idea.lanyus.com/ 获取注册码. 2.填入下面的license server: http://intellij.mandroid.cn/ http://ide ...

  10. #Java学习之路——基础阶段(第八篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...