处理集合还是只会for循环?那你该了解了解Stream API了

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了处理集合还是只会for循环?那你该了解了解Stream API了相关的知识,希望对你有一定的参考价值。

参考技术A

我: 哎,小花,面试去了吗?有问到Java 8 的新特性吗?

小花: Hey,Morty,多亏了你之前跟我详细讲解了Java8 的时间日期API,可让我显摆了一把。不过面试官说Java8的新特性可不止这一个,还有其他几个更重要的特性,比如 Stream API ,那究竟是什么神奇的特性呢?

我: Stream啊,是一个功能强大的新特性呢。简单来说, 是为了增强容器对元素的操作能力而提供给开发者的 。它们都被放在了 java.util.stream包 下。

而且,如果你知道Java8 的 Lambda表达式 ,那配合起来使用, 可以非常便捷地操作大批量集合对象。

小花: 天呐,这感觉咋这么牛叉嘞!以前我要是想处理一个List集合基本都是for循环,要么就是增强for循环。那这么说这个Stream完全可以替代for循环了?

我: 对了,你一提到for循环,这里就不得不说上一说。像我们以前通过for循环来处理集合对象比如List的时候, 属于命令式编程 ,这个很好理解,简单的说就是我们 每一句指令的含义都非常清晰,一句指令,一条操作,一一对应。 而使用Stream API代替for循环,成为 函数式编程 ,我们 通过简洁的语法,来调用一系列函数式语句 ,使其完成多步操作,这样不仅可以极大地精简代码,同时也不会因为过多的执行步骤导致无法及时有效地发现bug,从而极大地简化了编程。

小花: 真厉害,那你快说一说这个Stream到底该咋用呢?

我: 先别着急,在介绍用法之前,我们先来说说Stream, 流的概念

说起来这个概念还是来自于一些其他的函数式编程语言。你可以将流想象成一个车间的流水线。这个流水线上,可以给产品进行 筛选、加工、再包装 。它 本身不具备存储功能 ,因此也 不属于数据结构

刚刚提到流水线的加工操作,但是Stream不同,它无法修改数据源,比如,Stream的filter操作会产生一个不包含过滤元素的新的Stream,而不是从source中删除它们。另外, 所有的Stream操作必须以Lambda表达式作为参数

值得注意的是, Stream操作实际上是增强for循环的函数编程变式,没有元素下标的访问方式。

还有就是, 流可以转换成数组或者List ,流的操作也分为三类,分别是:Intermediate、Terminal、short-circuiting ,其中Intermidiate操作永远是惰性的。

小花: 这三个类型的操作分别都是什么意思呢?惰性又是代表什么意思呢?

我:Intermediate代表“中间的”,它表示流的中间操作,它的作用主要是打开流,做某种程度的映射、过滤,然后返回一个新的流,交给下一个操作继续处理 。脑海中要时刻想象流水线上的操作。这类操作是惰性的,什么意思呢?就是说 在程序调用的时候,其实这类操作并没有真正的执行,只有在程序真正运行到这个位置的时候,才会执行,这就是惰性

小花: 哦,有点意思,那另外两个呢?

我: Terminal的意思是“最终的”,它的概念与Intermediate相对, 是表示流操作的最后一项。一个流只能有一个Terminal操作,同时,Terminal操作的执行,才会真正开始流的遍历,并产生一个最终结果。

short-circuiting表示“短回路”操作。这个我们后面再慢慢体会。

小花: 来说说常规操作吧。

我: 恩,首先,是创建流。

如果你手里有一个数组或者是List集合,可以参考这样的写法:

小花: 很简单嘛,那拿到这个流之后我们能做哪些事情呢?

我: 那我们就来说说应用案例。首先是 映射操作 。首先,假设我们有这样一个记录名字的集合生成的流:

流的map()函数可以将输入流中的每一个元素映射为输出流中的另一个元素。比如,如果希望将所有的元素变成大写,可以这样写:

小花: 哇,这样只需要一条语句就完成了整个循环操作,还真是比传统的命令式编程简洁了不少呢,不过这样一来信息量也增大了,可读性倒是有所下降。

我: 的确是这样,封装的特点就是隐藏实现细节,从这一层面上来说的确是增加了程序的理解难度,不过瑕不掩瑜,它强大的功能还远不止这些。

我们再来看接下来的场景。如果你希望将两个List集合合并在一起,你会怎么做呢?

小花: 要是我,我就直接调用 addAll() 方法,将其中一个List追加到另一个List的末尾。

我: 那在如果我在合并的过程中还想加点操作呢?

小花: 你想干嘛?

我: 考虑这样的场景,如果希望将两个集合合并在一起,并且在合并的时候顺便做一些处理,那应该怎么写呢?

可以看到,在合并的过程中,我还将所有的名字都变成了小写,这样一条语句就可以完成所有的操作。

小花: 你先等会!还可以这么写?我好想有点感觉了。

我: 其实本来也不难,我们接着来讨论一下筛选操作。流的filter()函数可以对集合中的元素进行筛选:

还有一个我个人比较常用的函数—— forEach() 它可以接收一个Lambda表达式,然后在每一个元素上执行该表达式 。但是也会有诸多不便,比如, 无法修改自己包含的本地变量值,也无法return 提前返回。

小花: 恩,是的呢,真是一把双刃剑,虽然好用,但是却需要更加细心才能熟练运用。

我: 恩,的确是这样,Java8 提供的这套Stream API还包含很多特别有意思的函数。比如聚合操作的reduce,来感受一下:

还有limit返回Stream的前面的n个元素,skip扔掉前面n个元素:

还有排序操作:

小花: 真是越看越感觉强大。

我: 这种流式API一旦运用熟练,甚至可以代替一部分数据库的操作。如果想了解跟多的Stream的细节,你可以查看java.util.stream包下的类库。剩下的,就是需要在不断的实践中多总结和运用了。

---专注IT职场经验、IT技术分享的灵魂写手---

---每天带你领略IT的魅力---

---期待与您陪伴!---

以上是关于处理集合还是只会for循环?那你该了解了解Stream API了的主要内容,如果未能解决你的问题,请参考以下文章

java中for循环遍历map集合,再不了解你就out啦

了解Python控制流语句——for 循环

你该了解的10个 Python 模块

消息中间件你该了解的秘密

数据太大?你该了解Hadoop分布式文件系统

听说你30+了,还只会点点点功能测试,给你汇总了100种你该加强的地方,赶紧收藏吧