流是 从 源生成的 元素序列。
流是 从支持数据处理操作的 源生成的 元素序列。
数据处理操作 如filter、map、reduce、find、match、sort等。
流操作有两个重要的特点:
- 流水线
- 内部迭代
集合与流区别
粗略地说,集合与流之间的差异就在于什么时候进行计算。集合是一个内存中的数据结构,它包含数据结构中目前所有的值——集合中的每个元素都得先算出来才能添加到集合中。(
相比之下,流则是在概念上固定的数据结构(你不能添加或删除元素),其元素则是按需计算的。
有点抽象类比为生产手机的流水线吧:集合是一堆生产好的手机,想放进去一个手机,那么这个手机必须生产好的。流是在流水线上的还未生产好的手机,流水线上不能拿走一个,也不能随意放上去一个,流水线上会有一些操作。
遍历
流只能遍历一遍!
List<String> title = Arrays.asList("Java8", "In", "Action");
Stream<String> s = title.stream();
s.forEach(System.out::println); //成功遍历
s.forEach(System.out::println);//java.lang.IllegalStateException:流已被操作或关闭
集合:外部迭代
流:内部迭代 内部迭代时,项目可以透明地并行处理,或者用更优化的顺序进行处理。
流操作
List<String> names = menu.stream()
.filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.limit(3)
.collect(toList());
你可以看到两类操作:
-
filter、map和limit可以连成一条流水线;
-
collect触发流水线执行并关闭它。
中间操作
中间操作返回的还是流,例如上面代码的filter、map。除非流水线上触发一个终端操作,否则中间操作不会执行任何处理——它们很懒。
利用流的延迟性质进行的优化:
- 这是因为limit操作和一种称为短路的技巧。
- 尽管filter和map是两个独立的操作,但它们合并到同一次遍历中了(我们把这种技术叫作循环合并)。
终端操作
终端操作会从流的流水线生成结果。其结果是任何不是流的值。流操作中可以据此判断一个操作是中间操作还是终端操作。
long count = menu.stream()
.filter(d -> d.getCalories() > 300)
.distinct()
.limit(3)
.count();//流水线中最后一个操作count返回一个long,这是一个非Stream的值。
使用流
- 一个数据源(如集合)
- 一个中间操作链,形成一条流的流水线
- 一个终端操作,执行流水线,并能生成结果
所以
-
流是“从支持数据处理操作的源生成的一系列元素”。
-
流利用内部迭代:迭代通过filter、map、sorted等操作被抽象掉了。
-
流操作有两类:中间操作和终端操作。
-
filter和map等中间操作会返回一个流,并可以链接在一起。可以用它们来设置一条流水线,但并不会生成任何结果。
-
forEach和count等终端操作会返回一个非流的值,并处理流水线以返回结果。
-
流中的元素是按需计算的。