java 8 stream reduce详解和误区
java 8 stream reduce详解和误区
简介
Stream API提供了一些预定义的reduce操作,比如count(), max(), min(), sum()等。如果我们需要自己写reduce的逻辑,则可以使用reduce方法。
本文将会详细分析一下reduce方法的使用,并给出具体的例子。
reduce详解
Stream类中有三种reduce,分别接受1个参数,2个参数,和3个参数,首先来看一个参数的情况:
Optional<T> reduce(BinaryOperator<T> accumulator);
该方法接受一个BinaryOperator参数,BinaryOperator是一个@FunctionalInterface,需要实现方法:
R apply(T t, U u);
accumulator告诉reduce方法怎么去累计stream中的数据。
举个例子:
List<Integer> intList = Arrays.asList(1,2,3);
Optional<Integer> result1=intList.stream().reduce(Integer::sum);
log.info("{}",result1);
上面的例子输出结果:
com.flydean.ReduceUsage - Optional[6]
一个参数的例子很简单。这里不再多说。
接下来我们再看一下两个参数的例子:
T reduce(T identity, BinaryOperator<T> accumulator);
这个方法接收两个参数:identity和accumulator。多出了一个参数identity。
也许在有些文章里面有人告诉你identity是reduce的初始化值,可以随便指定,如下所示:
Integer result2=intList.stream().reduce(100, Integer::sum);
log.info("{}",result2);
上面的例子,我们计算的值是106。
如果我们将stream改成parallelStream:
Integer result3=intList.parallelStream().reduce(100, Integer::sum);
log.info("{}",result3);
得出的结果就是306。
为什么是306呢?因为在并行计算的时候,每个线程的初始累加值都是100,最后3个线程加出来的结果就是306。
并行计算和非并行计算的结果居然不一样,这肯定不是JDK的问题,我们再看一下JDK中对identity的说明:
identity必须是accumulator函数的一个identity,也就是说必须满足:对于所有的t,都必须满足 accumulator.apply(identity, t) == t
所以这里我们传入100是不对的,因为sum(100+1)!= 1。
这里sum方法的identity只能是0。
如果我们用0作为identity,则stream和parallelStream计算出的结果是一样的。这就是identity的真正意图。
下面再看一下三个参数的方法:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
和前面的方法不同的是,多了一个combiner,这个combiner用来合并多线程计算的结果。
同样的,identity需要满足combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
大家可能注意到了为什么accumulator的类型是BiFunction而combiner的类型是BinaryOperator?
public interface BinaryOperator<T> extends BiFunction<T,T,T>
BinaryOperator是BiFunction的子接口。BiFunction中定义了要实现的apply方法。
其实reduce底层方法的实现只用到了apply方法,并没有用到接口中其他的方法,所以我猜测这里的不同只是为了简单的区分。
总结
虽然reduce是一个很常用的方法,但是大家一定要遵循identity的规范,并不是所有的identity都是合适的。
本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/stream-reduce
欢迎关注我的公众号:程序那些事,更多精彩等着您!
更多内容请访问 www.flydean.com
java 8 stream reduce详解和误区的更多相关文章
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java8引入了 ...
- Java 8 Stream API 详解
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggregate operation),或者大批量数据操作 (b ...
- Java8的Stream语法详解(转载)
1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel agg ...
- Java8初体验(二)Stream语法详解(转)
本文转自http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com上篇文章Java8初体验(一 ...
- Java8初体验(二)Stream语法详解---符合人的思维模式,数据源--》stream-->干什么事(具体怎么做,就交给Stream)--》聚合
Function.identity()是什么? // 将Stream转换成容器或Map Stream<String> stream = Stream.of("I", & ...
- Storm 第三章 Storm编程案例及Stream Grouping详解
1 功能说明 设计一个topology,来实现对文档里面的单词出现的频率进行统计.整个topology分为三个部分: SentenceSpout:数据源,在已知的英文句子中,随机发送一条句子出去. S ...
- Java 8 Lambda 表达式详解
一.Java 8 Lambda 表达式了解 参考:Java 8 Lambda 表达式 | 菜鸟教程 1.1 介绍: Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性. La ...
- java反射机制深入详解
java反射机制深入详解 转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...
- 国际化,java.util.ResourceBundle使用详解
java.util.ResourceBundle使用详解 一.认识国际化资源文件 这个类提供软件国际化的捷径.通过此类,可以使您所编写的程序可以: 轻松地本地化或翻译成不同的 ...
随机推荐
- spring-cloud-gateway降级
前言 本文主要研究一下 spring cloud gateway 如何集成 hystrix. 当下游接口负载很大,或者接口不通等其他原因导致超时,如果接口不熔断的话将会影响到下游接口得不到喘息,网关也 ...
- 1.Metasploit介绍与基本命令
Metasploit体系框架介绍 Metasploit是目前世界上领先的渗透测试工具,也是信息安全与渗透测试领域最大的开源项目之一.它彻底改变了我们执行安全测试的方式. Metasploit之所以流行 ...
- php依赖注入与容器,Container,控制反转
依赖注入与Ioc容器 概念: 容器:可以理解为用来存放某个东西的物品(篮子?),存放的东西取决于你想往里面放点什么.在这里,我们是存放某个类,类的描述或者一个返回类实例的闭包函数. Ioc(Inver ...
- 程序员的娱乐项目:Arduino 之 HelloWorld
文章更新于:2020-03-14 文章目录 一.什么是Arduino 二.怎么购买Arduino 三.Arduino都是有那些版本 四.哪里可以找到Arduino的资料 五.Arduino 的供电电源 ...
- 家庭记账本app进度之关于单选按钮的相关操作(添加点击按钮事件以及点击单选更改事件)
这次主要是通过代码实现了android中的相关单选按钮的相关操作,之后再最下面有一个按钮,当点击这个按钮的时候,会获取当上面的相关信息,之后再下方会进行相应的文字显示,获取的信息不同显示的信息也不会一 ...
- Mysql 临时表+视图
原文地址:http://www.cnblogs.com/mrdz/p/6195878.html 学习内容: 临时表和视图的基本操作... 临时表与视图的使用范围... 1.临时表 临时表:临时表, ...
- 一口气说出 4种 LBS “附近的人” 实现方式,面试官笑了
引言 昨天一位公众号粉丝和我讨论了一道面试题,个人觉得比较有意义,这里整理了一下分享给大家,愿小伙伴们面试路上少踩坑.面试题目比较简单:"让你实现一个附近的人功能,你有什么方案?" ...
- 邮件退信“Remote Server returned '420 4.2.0 Recipient deferred because there is no Mdb'”
标题是一个近期遇到的NDR 对于Exchange运维工作者,NDR通常给了我们较为清晰的排错方向,我们先看一下退信的原因, 我的一台MailBox报错“远程服务器返回‘420 4.2.0’接受延迟,因 ...
- windows 环境下dos 命令符下进D盘(非c盘系统盘)根目录
怎么进? 先 cd D: 然后 直接 D: 即可到D盘根目录,至于为啥要输入2遍D 才进D盘根目录,这就是windows的规定
- CentOS 配置OOM监控报警
由于程序设计不合理或者瞬间高并发访问时,很有可能会触发OOM(Out of memory),这里指的是操作系统级别的OOM.具体什么是OOM,以及怎样发生这里不在赘述,因为笔者认为这是IT从业工作者的 ...