首页 > 技术文章 > Stream 什么是流

Mr-O-O 2019-10-21 21:51 原文

流是 从 源生成的 元素序列。

流是 从支持数据处理操作的 源生成的 元素序列。

数据处理操作 如filter、map、reduce、find、match、sort等。

流操作有两个重要的特点:

  1. 流水线
  2. 内部迭代

集合与流区别

粗略地说,集合与流之间的差异就在于什么时候进行计算。集合是一个内存中的数据结构,它包含数据结构中目前所有的值——集合中的每个元素都得先算出来才能添加到集合中。(

相比之下,流则是在概念上固定的数据结构(你不能添加或删除元素),其元素则是按需计算的。

有点抽象类比为生产手机的流水线吧:集合是一堆生产好的手机,想放进去一个手机,那么这个手机必须生产好的。流是在流水线上的还未生产好的手机,流水线上不能拿走一个,也不能随意放上去一个,流水线上会有一些操作。

遍历

流只能遍历一遍!

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的值。

使用流

  1. 一个数据源(如集合)
  2. 一个中间操作链,形成一条流的流水线
  3. 一个终端操作,执行流水线,并能生成结果

所以

  • 流是“从支持数据处理操作的源生成的一系列元素”。

  • 流利用内部迭代:迭代通过filter、map、sorted等操作被抽象掉了。

  • 流操作有两类:中间操作和终端操作。

  • filter和map等中间操作会返回一个流,并可以链接在一起。可以用它们来设置一条流水线,但并不会生成任何结果。

  • forEach和count等终端操作会返回一个非流的值,并处理流水线以返回结果。

  • 流中的元素是按需计算的。

推荐阅读