本文为转载 原文链接:http://www.cnblogs.com/Dorae/p/7779246.html
author:Author:Dorae Date:2017年11月2日19:10:39
这篇博客内容还未看,内容正确与否,请自行判断。
上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比较大且非常重要的改动就是Stream。在这篇文章中,将会对流的实现原理进行深度,解析,具体关于如何使用,请参考《Java8函数式编程》。
常用的流操作
在深入原理之前,我们有必要知道关于Stream的一些基础知识,关于Stream的操作分类,如表1-1所示。
表1-1 Stream的常用操作分类(表格引自这里)
如表1-1中所示,Stream中的操作可以分为两大类:中间操作与结束操作,中间操作只是对操作进行了记录,只有结束操作才会触发实际的计算(即惰性求值),这也是Stream在迭代大集合时高效的原因之一。中间操作又可以分为无状态(Stateless)操作与有状态(Stateful)操作,前者是指元素的处理不受之前元素的影响;后者是指该操作只有拿到所有元素之后才能继续下去。结束操作又可以分为短路与非短路操作,这个应该很好理解,前者是指遇到某些符合条件的元素就可以得到最终结果;而后者是指必须处理所有元素才能得到最终结果。
原理探秘
在探究Stream的执行原理之前,我们先看如下两段代码(本文将以code_1为例进行说明):
code_1
public static void main(String[] args) {
List<String> list = Lists.newArrayList(
"bcd", "cde", "def", "abc");
List<String> result = list.stream()
//.parallel()
.filter(e -> e.length() >= 3)
.map(e -> e.charAt(0))
//.peek(System.out :: println)
//.sorted()
//.peek(e -> System.out.println("++++" + e))
.map(e -> String.valueOf(e))
.collect(Collectors.toList());
System.out.println("----------------------------");
System.out.println(result);
}
code_2
public void targetMethod() {
List<String> list = Lists.newArrayList(
"bcd", "cde", "def", "abc");
List<String> result = Lists.newArrayListWithCapacity(list.size());
for (String str : list) {
if (str.length() >= 3) {
char e = str.charAt(0);
String tempStr = String.valueOf(e);
result.add(tempStr);
}
}
System.out.println("----------------------------");
System.out.println(result);
}
很明显,在最终结果上而言,code_1与code_2是等价的。那么,Stream是怎么做的呢?显然不是每次操作都进行迭代,因为这对于执行时间与存储中间变量来说都将是噩梦。
要解决的问题
显然,如果code_2只对集合迭代了一次,也就是说相当高效。那么这么做有没有弊端?有!模板代码、中间变量、不利于并行都是其存在的问题。但是按着code_2的思路可以知道有以下几个问题需要解决:
- 如何记录每次操作?