Stream是java8中处理计划的关键抽象概念,它可以指定你希望对集合进行的操作,但是将执行操作的时间交给具体实现来决定。
1、从迭代器到Stream操作
Stream表面上看与一个集合很类似,允许你改变和获取数据。但是实际上它与集合有很大区别:
a、它自己不会存储元素。元素被存储在底层的集合中,或根据需要产生出来。
b、Stream操作符不会改变源对象。它会返回一个持有结果的新Stream。
c、Stream操作符可能是延迟执行的。它会等到需要结果时才执行。
Stream表达式比循环的可读性好,并发很容易进行,只要用parallelStream方法,就可以让Stream API并行执行过滤和统计操作。
Stream遵循“做什么,而不是怎么去做”的原则。当使用Stream时,会通过三个阶段来建立一个操作流水线:
a、创建一个Stream。
b、在一个或多个步骤中,指定将初始Stream转换为另一个Stream的中间操作。
c、使用一个终止操作来产生一个结果。该操作会强制它之前的延迟操作立即执行。在这之后,该Stream就不会再被使用了。
2、创建Stream
通过java8在Collection接口中新添加的stream方法,可以将任何集合转化为一个stream。如果你面对的是一个数组,也可以使用静态的Stream.of方法将它转化为一个Stream。of方法接受可变长的参数,因此你可以构造一个含有任意个参数的Stream。
使用Arrays.stream(array,from,to)方法将数组的一部分转化为Stream。
要创建一个不含任何元素的Stream,可以使用静态的Stream.empty方法。
Stream接口有两个用来创建无限Stream的静态方法。generate方法接受一个无参的函数。要创建一个形如0 1 2 3 ...的无限序列,可以使用iterate方法。Stream接口有一个父接口AutoCloseable。当在某个Stream上调用close方法时,底层的文件也会被关闭。为了确保关闭文件,最好使用java7中提供的try-with-resource语句,使得当try语句块或者抛出异常时,Stream与其关联的底层文件都将被关闭。
3、filter、map和flatMap方法
流转换是指从一个流中读取数据,并将转换后的数据写入到另一个流中。
filter方法的参数是一个Predicate<T>对象——即一个从T到boolean的函数。我们经常需要对一个流中的值进行某种形式的转换,可以考虑使用map方法,并传递给它一个执行转换的函数。
4、提取子流和组合流
Stream.limit(n)会返回一个包含n个元素的新流(如果原始流的长度小于n,则会返回原始的流)。这个方法特别适用于裁剪指定长度的流。
Stream.skip(n)则会丢弃前面的n个元素。
5、有状态的转换
前面介绍的流都是无状态的。当从一个已过滤或已映射的流中获取某个元素时,结果并不依赖于之前的元素。除此之外,java8中也提供了有状态的转换。例如distinct方法会根据原始流中的元素返回一个具有相同顺心、预制了重复元素的新流,该流须记住之前已读取的元素。Collects.sort会对原有的集合进行排序,而Stream.sorted会返回一个新的已排序的流。
6、简单的聚合方法
聚合方法都是终止操作,当一个流应用了终止操作后,它就不能再应用其他的操作了。
7、Optional类型
Optional<T>对象或者是一个T类型对象的封装,或者表示不是任何对象。它比一般指向T类型的引用更安全,因为它不会返回null——在你正确使用它的前提下才会更安全。
高效使用Optional的关键在于,使用一个或者接受正确值、或者返回另一个替代值的方法。创建可选值。使用flatMap来组合可选值函数。
8、聚合操作
如果你希望对元素求和,或者以其他方式将流中的元素组合为一个值,可以使用聚合方法。
9、收集结果
当你处理完流之后,你通常只是想查看一下结果,而不是将他们聚合为一个值。可以调用iterator方法来生成一个传统风格的迭代器,用于访问元素。