一、从迭代器(Iterator)到流(Stream)
Stream
Stream是Java SE8中新加入的类库。流(stream)提供了一种相对于集合(collections)更高级概念的具体数据视图。通过流的使用,你能清楚的知道你做了什么,但关心怎么做。它已经脱离了计算过程的实现。例如,你想计算一个已知属性的平局值。那就列举出数据源,属性还有可以最优化计算的流,例如通过多线程的方式计算综合和数量并且返回结果。
—— [翻译自Core.Java-Volume.II.Advanced.Features.10th.Edition Character 1]
ps:在学习Stream之前,请确保你的jdk是1.8版本,并且具有一定的Lamda表达式知识。
通常来说操作一个集合,都是遍历这个集合然后对其中的每一个元素进行操作。例如,我们想知道一段文字中长单词的数量。
我们有如下的一段文本存在项目中的test.txt中:
The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform. A key element of Spring is infrastructural support at the application level: Spring focuses on the “plumbing” of enterprise applications so that teams can focus on application-level business logic, without unnecessary ties to specific deployment environments.
—— Spring Framework
将文件中的文本加载到内存中,并将其切割为字符串转换成一个List:
//从内存中加载文件中的内容
String contents = new String(Files.readAllBytes(Paths.get("test.txt")), StandardCharsets.UTF_8);
//通过空格将段落分割成单个字符串转换成List
List<String> words = Arrays.asList(contents.split("\\PL+"));
通常来说,我们会通过遍历的方式来取得每个元素:
long count = 0L;
for (String w : words) {
if (w.length() > 8) count++;
}
如果使用流进行上面的操作:
//filter方法筛选出了符合条件(字符串长度大于8)的单次,count函数聚合了数量
long count = words.stream() .filter(w -> w.length() > 8) .count();
使用流的方式看起来比遍历更简单,因为你不必了解每次筛选和计数的过程。方法名告诉了你代码将要执行的结果。此外,循环提供了每次操作的具体过程,流却可以用任意你想要的方式执行,也能准确的获取结果.
关于流
流遵循”什么,而不是怎么”原则。在前面的流示例中,我们描述了要做的事:获取长单词并且计数。我们不在意用什么规则,在哪个线程,将要发生什么。在差异上来说,在循环的开始就规定了一些细则尤其是计算怎么工作,因此这会放弃很多优化的机会。
流似乎在外表上看着比集合要简单的,他允许你变换和取回数据。但下面是一些具体的差异:
1. 流不存储对象,这些对象可能存储在底层的集合或者在需要的时候在产生。
2. 流的操作不改变数据源。例如筛选(filter)方法不从一个新的流中移除元素,但是他生成一个和现在不同的新流。
3. 流的操作在必要时是惰性的(lazy)。这会意味着,当需要结果的这个操作才会被执行。例如,你只想要前五个长单词而不是全部的,filter方法将会在获取到五个结果的时候停止过滤.当作为结果考虑的时,你甚至可以拥有无限的流.
下面是使用流的典型流程,你的操作应当遵守下面三条过程:
1. 创建一个流。
2. 通过一步或者很多步骤创建出中间操作的流。
3. 为结果创建一个最终的收集方。这个操作可以是惰性的。在这之后这个流就不能再使用了。
下一篇文章会介绍如何创建一个流。