手把手带你体验Stream流
前言
只有光头才能变强。
文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y
上一篇讲解到了Lambda表达式的使用《最近学到的Lambda表达式基础知识》,还没看的同学可以先去阅读一下哈~
相信也有不少的同学想要知道:Lambda表达式在工作中哪个场景会用得比较多?跟Lambda搭边的,使用Stream流会比较多
一般人第一次看Stream流的代码,都会有点看不懂(它的代码看起来好像就不是写Java一样.),希望这篇文章能带大家入个门
一、体验Stream流
大家在自学时,大多数会学过一个程序:算出从数组元素的和
,当时我们是怎么写的?一般来说是这样的:
public static void main(String[] args) { int[] nums = { 1, 2, 3 }; int sum = 0; for (int i : nums) { sum += i; } System.out.println("结果为:" + sum); }
如果我们使用Stream流的话,可以这样:
public static void main(String[] args) { int[] nums = { 1, 2, 3 }; int sum2 = IntStream.of(nums).sum(); System.out.println("结果为:" + sum2); }
从代码量上可以明显看出,用Stream流的方式会少一些。
我理解的Stream流编程就是:某些场景会经常用到操作(求和/去重/过滤....等等),已经封装好API给你了,你自己别写了,调我给你提供的API就好了。
1.1 支持并发
回到我们最原始的代码:
public static void main(String[] args) { int[] nums = { 1, 2, 3 }; int sum = 0; for (int i : nums) { sum += i; } System.out.println("结果为:" + sum); }
如果我们想要for
循环的内部支持并发的话,显然不太好去写。但使用Stream流的方式,调用一个方法就可以支持并发(parallel):
public static void main(String[] args) { int[] nums = { 1, 2, 3 }; int sum2 = IntStream.of(nums).parallel().sum(); System.out.println("结果为:" + sum2); }
优点:调API肯定是比自己写的代码量要少。
缺点:不太方便调试
为什么要使用Stream流在我看来就是以上两个原因:
- 方便并发
- 代码量少(直接调用API)
二、如何使用Stream流?
使用Stream流分为三步:
- 创建Stream流
- 通过Stream流对象执行中间操作
- 执行最终操作,得到结果
2.1 创建流
创建流我们最常用的就是从集合中创建出流
/** * 返回的都是流对象 * @param args */ public static void main(String[] args) { List<String> list = new ArrayList<>(); // 从集合创建 Stream<String> stream = list.stream(); Stream<String> stream1 = list.parallelStream(); // 从数组创建 IntStream stream2 = Arrays.stream(new int[]{2, 3, 5}); // 创建数字流 IntStream intStream = IntStream.of(1, 2, 3); // 使用random创建 IntStream limit = new Random().ints().limit(10); }
2.2 执行中间操作
怎么理解中间操作?意思是这样的:在上面我们已经能创建出Stream了,我们是对Stream进行操作,对Stream操作返回完返回的还是Stream,那么我们称这个操作为中间操作。
比如,我们现在有个字符串my name is 007
,代码如下:
String str = "my name is 007"; Stream.of(str.split(" ")).filter(s -> s.length() > 2) .map(s -> s.length()).forEach(System.out::println);
分解:
1、从字符串数组创建出流对象:
Stream<String> split = Stream.of(str.split(" "));
2、通过流对象的API执行中间操作(filter),返回的还是流对象:
Stream<String> filterStream = split.filter(s -> s.length() > 2);
3、通过返回的流对象再执行中间操作(map),返回的还是流对象:
Stream<Integer> integerStream = filterStream.map(s -> s.length());
因为中间操作返回的都是流对象,所以我们可以链式调用。
注意:Stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行(惰性求值)。
比如说,peek()
是一个中间操作,返回的是Stream流对象,只要它不执行最终的操作,这个Stream是不会执行的。
String str = "my name is 007"; Stream.of(str.split(" ")).peek(System.out::println); // 不会有信息打印
2.3 执行最终操作
最终操作返回的不再是Stream对象,调用了最终操作的方法,Stream才会执行。还是以上面的例子为例:
String str = "my name is 007"; Stream.of(str.split(" ")).peek(System.out::println).forEach(System.out::println)
这次我们加入了最终操作,所以这次的Stream流会被执行,由于中间操作和最终操作都是执行打印,所以会看到两次打印:
至于中间操作和最终操作怎么区分,我们以返回值来看就行了。中间操作返回的是Stream实例对象,最终操作返回的不是Stream实例对象:
最后
这篇文章主要跟大家一起初步认识一下Stream流,至于中间操作、最终操作的API讲解我就不写了(网上的教程也很多)
使用Stream的原因我认为有两个:
- JDK库提供现有的API,代码写起来简洁优化
- 方便并发。大家可以记住一个结论:在多核情况下,可以使用并行Stream API来发挥多核优势。在单核的情况下,我们自己写的
for
性能不比Stream API 差多少
参考资料:
乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,关注即可获取!
觉得我的文章写得不错,点赞!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
《阿里云前端技术周刊》第二十期
作者: @凌焘 校对:@行剑 @语安 知乎:阿里云中台前端/全栈团队专栏 Github:阿里云前端技术周刊 给我们投稿:传送门 参与交流:传送门 前端速报 Node v12.9.0发布,对fs、http、stream等多个模块的功能进行了更新。传送门 vue-cli发布v4.0.0-rc.0版本,为build命令增加--inline-vue的flag,避免了Vue在wc模式下的外化,同时修复了部分bug。传送门 Eslint v6.2.1发布,对eslint安全功能相关的bug进行了修复。[传送门](https://eslint.org/blog/2019/08/eslint-v6.2.1-released) 趣前端 开源项目又新增一个广告位?许多流行的JavaScript开源库开始在终端中展示广告。传送门 用代码为自己做一件专属T恤!在codeyourownshirt中可以使用canvas为自己创造独一无二的图案,然后用图案制作一件T恤。传送门 RadialMenu.js:一款易用的圆形径向菜单库,可以唤起美观的圆形菜单,PC/移动端多平台适用。传送门 编者推荐 JavaScript...
- 下一篇
Glide缓存流程
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/cPLkefpEb3w12-uoiqzTig 作者:连凌能 Android上图片加载的解决方案有多种,但是官方认可的是Glide。Glide提供简洁易用的api,整个框架也方便扩展,比如可以替换网络请求库,同时也提供了完备的缓存机制,应用层不需要自己去管理图片的缓存与获取,框架会分成内存缓存,文件缓存和远程缓存。本文不会从简单的使用着手,会把重点放在缓存机制的分析上。 一、综述 开始之前,关于Glide缓存请先思考几个问题: Glide有几级缓存? Glide内存缓存之间是什么关系? Glide本地文件IO和网络请求是一个线程吗?如果不是,怎么实现线程切换? Glide网络请求回来后数据直接返回给用户还是先存再返回? 加载开始入口从Engine.load()开始,先看下对这个方法的注释, 会先检查(Active Resources),如果有就直接返回,Active Resources没有被引用的资源会放入Memory Cache,如果Active Resources没有,会往下走。 ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果