Java8学习(4)-Stream流

Stream和Collection的区别是什么

流和集合的区别是什么?

粗略地说, 集合和流之间的差异就在于什么时候进行计算。集合是一个内存中的数据结构,它包含数据结构中目前所有的值--集合中的每个元素都得先计算出来才能添加到内存里。(你可以往集合里加东西或者删东西,但是不管什么时候,集合中的每个元素都是放在内存里的,元素都得计算出来才能成为集合的一部分。)

相比之下,流则是在概念上固定的数据结构(你不能添加或者删除元素),其元素则是按需计算的。这对编程有很大的好处。用户仅仅从流中提取需要的值,而这些值--在用户看不见的地方--只会按需生成。这是一种生产者 - 消费者的关系。从另一个角度来说,流就像一个延迟创建的集合:只有在消费者要求的时候才会计算值。

Stream是内部迭代

一个明显的区别是迭代方式不同。Collection需要手动for-each或者使用Iterator在外部迭代。而Stream则开启后可以直接对单个元素进行操作,内部帮你做好了迭代工作。

内部迭代的好处是可一个更好的并行。自己手写迭代需要处理好每次迭代的内容。为了提高执行效率,也许会把多个处理逻辑写到同一个遍历里。比如,有同事看到从scala转过来的同事的代码,说他写的代码经常重复好多次。scala是函数式语言,和流天然集成。而我们惯性的做法,还是把一堆操作逻辑写到同一个循环体中,来满足自己对所谓的性能要求的洁癖。这常常会使得可读性变差。很厌烦阅读超过100行的代码,尤其代码还有首尾同步处理的逻辑(for, try-catch),很容易出错。多写一次循环来做这些事情,心理又过不去。

Stream开启流之后,系统内部会分析对元素的操作是否可以并行,然后合并执行。也就是说,看起来,自己filter-map-filter-map-group很多次,但真实执行的时候并不是遍历了很多次。至于到底遍历了多少次。这是一个好问题,后面会说明这个问题。

使用流Stream的注意事项

流只能消费一次。比如,foreach只能遍历一次stream。再次则会抛异常。

流操作

针对流的操作方式两种:

中间操作

可以连接起来的流操作叫做中间操作。诸如filter或map等中间操作会返回另一个流。这让多个操作可以连接起来形成一个查询。但是,除非调用一个终端操作,比如collect,foreach, 否则中间操作不会执行----它们很懒。这是因为中间操作一般可以合并起来,在终端操作时一次性全部处理。

终端操作

关闭流的操作叫做终端操作。终端操作会从流的流水线生成结果。

使用流

本文demo源码: https://github.com/Ryan-Miao/someTest/tree/master/src/main/java/com/test/java8/streams

新建一个Entity作为基本元素。

package com.test.java8.streams.entity; /** * Created by Ryan Miao on 12/11/17. */ public class Dish { private final String name; private final boolean vegetarian; private final int calories; private final Type type; public Dish(String name, boolean vegetarian, int calories, Type type) { this.name = name; this.vegetarian = vegetarian; this.calories = calories; this.type = type; } public String getName() { return name; } public boolean isVegetarian() { return vegetarian; } public int getCalories() { return calories; } public Type getType() { return type; } public enum Type{ MEAT, FISH, OTHER } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyszzx.html