Java8 Stream流使用及其基本原理
Stream流,是对集合对象操作的增强
基本使用
比如有一个Person类的集合:List<Person> personList,可以通过stream()对集合中的元素进行操作,
下面的操作流程可以归纳为 过滤-映射-收集。
List<Integer> personIdList = personList.stream()
//选出年龄大于20的Person对象
.filter(person -> person.getAge() > 20)
//将Person对象映射成为它的属性id
.map(Person::getId)
//收集为List集合
.collect(Collectors.toList());
上述代码获取到了,年龄大于20岁的人id集合。
在 过滤-映射-收集 这个流程中:
过滤和映射属于中间操作,当操作结束时才会触发计算,可以高效地迭代大集合
收集属于结束操作,触发计算。
中间操作和结束操作
流操作可以分为 中间操作(惰性求值) 和 结束操作
中间操作指,操作过程中只记录操作而不做执行,直到执行结束操作,才会触发实际的操作,即惰性求值。
中间操作又分为:
无状态操作,元素处理不受之前元素影响,比如map()、filter()、skip()、peek()等
有状态操作,需要拿到所有元素才能进行,比如sorted()、limit()、distinct()等
结束操作是指,拿到所有元素后才能进行的操作。
结束操作又分为:
短路操作,遇到符合条件的元素后就可以终止,比如anyMatch()、findFirst()、findAny()等
非短路操作,需要处理所有元素,比如forEach()、collect()、max()、count()等。
例子
1.将List<Person>映射成一个Map,key为Person的id属性,value为Person实体类
Map<Integer, Person> PersonMap= personList.stream()
.collect(Collectors.toMap(Person::getId, person -> person));
2.得到一个Map<Integer,List<Person>>集合,key为Person的age属性,value是按年龄分组后的Person对象集合:
Map<Integer, List<Person>> personsMap = personList.stream()
.collect(Collectors.groupingBy(Person::getAge));
3.统计所有人年龄的总和:
int personAgeSum = personList.stream()
//根据age属性转换成IntStream
.mapToInt(Person::getAge)
.sum();
4.选出List集合中创建时间最晚的数据(createtime属性为Date类型)
UserInfo userInfoMax = userInfos.stream()
.max(Comparator.comparing(UserInfo::getCreateTime))
.get();
这里的max方法实际返回的是Optional<UserInfo>对象该对象可以通过orElse()方法设置对象UserInfo为null时的值:
UserInfo userInfoMax = userInfos.stream().max(Comparator.comparing(UserInfo::getCreateTime))
.orElse(为null时的值); //这里如果max返回的对象为null(一般情况不会是),会取orElse()中的值
5.将所有小写字母拼接起来
String concat = Stream.of("a", "B", "c", "D", "e", "F")
.filter(x -> x.compareTo("Z") > 0)
.reduce("", String::concat);
reduce方法的第一个参数是起始值,第二个参数是流中的元素,迭代流中的数据
也可以只传一个参数,即不指定起始值,这样会返回一个Optional对象
String concat = Stream.of("a", "B", "c", "D", "e", "F")
.filter(x -> x.compareTo("Z") > 0)
.reduce(String::concat)
.orElse("");
性能及基本原理简述
Stream 顾名思义,相当于批量处理数据的流水线。
在处理一般的数据量下,使用循环方式处理集合和通过stream方式处理集合的性能相差不大,但在数据里更大逻辑更复杂的情况下stream要更优。
而parallelStream并行流,利用多核处理器的优势,并行处理数据(这意味着所处理的数据,不应该和顺序相关,否则会因为并行得到错误的结果),能够显著的提高执行速度。
Stream处理过程简述:
首先将Collection转化为Stream,流上的每个结点都只会返回包含上一结点引用的中间结点,使结点们组成了一个双向链表结构,而不会立即进行任何数据处理。
每个中间操作都实现了Sink接口,实现了 makeSink()
方法用来返回自己的 Sink 实例,
只有当终止操作出现时,才开始将 Sink 实例化执行数据处理,
无状态操作的 Sink 接收到数据,会立即通知下游,有状态操作的 Sink 则会等要处理的数据处理完了才开始通知下游,
终止节点将数据收集起来后就完成了这次操作。
参考文章:
https://www.cnblogs.com/CarpenterLee/archive/2017/03/28/6637118.html
https://zhuanlan.zhihu.com/p/52579165
https://zhuanlan.zhihu.com/p/47478339
原文地址:https://www.cnblogs.com/gss128/p/11032504.html
- UVA 1030 - Image Is Everything【模拟+思维+迭代更新】
- C/C++中对链表操作的理解&&实例分析
- COGS 2482. Franky的胡子【二分,高精度】
- 【AlphaGo Zero 核心技术-深度强化学习教程代码实战02】理解gym的建模思想
- Kruscal(最小生成树)算法模版
- BZOJ 3680: 吊打XXX【模拟退火算法裸题学习,爬山算法学习】
- 区块链概况:什么是比特币
- 简化版桶排序操作模版
- BZOJ 3670: [Noi2014]动物园【KMP变形 】
- 【延迟注入】A5站长网某站存在SQL注入漏洞
- hihoCoder #1498 : Diligent Robots【数学】
- Codeforces Round #336 (Div. 2)【A.思维,暴力,B.字符串,暴搜,前缀和,C.暴力,D,区间dp,E,字符串,数学】
- 【防护】如何阻止SELECT * 语句
- COGS 862. 二进制数01串【dp+经典二分+字符串】
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 学习使用Material Design控件(四)Android实现标题栏自动缩放、放大效果
- Ubuntu 20.04 CUDA&cuDNN安装方法(图文教程)
- Android开发之基于DialogFragment创建对话框的方法示例
- Android图片压缩的实例详解
- Android编程之手机壁纸WallPaper设置方法示例
- 手把手教你在腾讯云上搭建hadoop3.x伪集群的方法
- Android从网络中获得一张图片并显示在屏幕上的实例详解
- Android ListView中headerview的动态显示和隐藏的实现方法
- Android编程使用Service实现Notification定时发送功能示例
- Android基于ViewFilpper实现文字LED显示效果示例
- Android ViewPager导航小圆点实现无限循环效果
- ViewPager打造轮播图Banner/引导页Guide
- Android 实现带字母索引的侧边栏功能
- Android实现简单底部导航栏 Android仿微信滑动切换效果
- Android中Handler与Message的简单实例