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使用详解 一.认识国际化资源文件 这个类提供软件国际化的捷径.通过此类,可以使您所编写的程序可以: 轻松地本地化或翻译成不同的 ...
随机推荐
- 马哥教育PYTHON相关基础 笔记
1 python 推荐书籍 <python Cookbook> <learn python the hard way> <google's python class> ...
- C/C++知识总结 二 C/C++基础知识
C/C++基础知识 C/C++基本格式说明 C/C++基本常识说明 C/C++基本格式说明 C语言基本格式 #include<stdio.h> //预处理文件 int main() //自 ...
- 如何优雅的将文件转换为字符串(环绕执行模式&行为参数化&函数式接口|Lambda表达式)
首先我们讲几个概念: 环绕执行模式: 简单的讲,就是对于OI,JDBC等类似资源,在用完之后需要关闭的,资源处理时常见的一个模式是打开一个资源,做一些处理,然后关闭资源,这个设置和清理阶段类似,并且会 ...
- Windows命令help的基本使用
- Round 1A 2020 - Code Jam 2020
Problem A. Pattern Matching 把每个字符串分成第一个之前,最后一个之后,中间的部分 三个部分 每个字符串的中间的部分可以直接拼接 前后两个部分需要判断下是否合法 #inclu ...
- 如何优雅的关闭基于Spring Boot 内嵌 Tomcat 的 Web 应用
背景 最近在搞云化项目的启动脚本,觉得以往kill方式关闭服务项目太粗暴了,这种kill关闭应用的方式会让当前应用将所有处理中的请求丢弃,响应失败.这种形式的响应失败在处理重要业务逻辑中是要极力避免的 ...
- ASP.NET Core技术研究-探秘依赖注入框架
ASP.NET Core在底层内置了一个依赖注入框架,通过依赖注入的方式注册服务.提供服务.依赖注入不仅服务于ASP.NET Core自身,同时也是应用程序的服务提供者. 毫不夸张的说,ASP.NET ...
- JAVA自动化之Junit单元测试框架详解
一.JUnit概述&配置 1.Junit是什么? Junit是一个Java 编程语言的开源测试框架,用于编写和运行测试.官网 地址:https://junit.org/junit4/ 2.Ma ...
- MTK Androiod HAL如何向上层提供接口
Android中HAL如何向上层提供接口总结 转自:http://blog.csdn.net/flydream0/article/details/7086273 参考文献: http://blog.c ...
- 使用Maven Archetype创建Java项目模板
1.over view 简而言之,Archetype是一个Maven项目模板工具包.原型被定义为一种原始的模式或模型,所有其他同类的东西都是从中产生的.当我们试图提供一个提供生成Maven项目的一致方 ...