对Lambda的一些感悟--stream(一)

字数 1458阅读 56

前言

Stream并不是一种数据结构,只是数据源的一种视图(数据源包括:数组,Java容器,I/O channel)。得到这种视图需要调用工具方法:Collection.stream(),Collection.parallelStream(),Arrays.stream(T[] array)。

stream和collections的区别

1,无存储:stream只是数据源(集合)的一个视图,stream并不存储值。

2,函数式编程风格:对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作,不会删除数据源中被过滤的元素,而是会产生一个不包含被过滤元素的新stream。

3,惰性执行:stream上的操作(过滤、映射、排序以及去重等)不会立即执行,只有等到真正需要结果的时候才会执行。

4,一次消费:stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

对stream操作:中间操作和结束操作

1,中间操作:惰性执行,调用中间操作只会生成一个标记了该操作的新stream。

2,结束操作:触发实际计算,把所有中间操作积攒并以pipeline方式执行,减少迭代次数。计算完成后stream就会失效。

中间操作使用惰性执行和pipeline里的其他操作混合在一起。和惰性执行对应的是急性执行,急性执行:需要在方法返回前对所有的操作(一个操作就需要对数据源进行一次遍历)。pipeline:数据源--惰性执行--惰性执行--急性执行。pipeline中的惰性执行几乎不可见,pipeline每一轮操作都会接收输入流中的元素,进行转换,然后把转换后的结果传给下一轮操作。

大白话来说明一下:有一个保存"人"的集合,现在需要选出年龄在18到22岁,身高165以上的女性的人数。按照stream的惰性操作,现在pipeline里面的有三个惰性执行操作:年龄,身高,性别,求和。从数据源到中间操作到最后的结束操作,在求和开始后,把年龄,身高,性别三个惰性执行动作混合在一起对数据源进行一次遍历(调用数据源的stream方法,得到视图后,在视图上执行惰性操作,每一个惰性执行后会产生一个新的stream(视图),并把新的stream传给下一个惰性执行造作,这样就达到只对集合遍历一次)。最后结束操作(求和)来触发实际计算得到最终的结果。并且stream失效。

返回值是stream大都是中间操作,如果不是则是结束操作。

并行

流水线既可以串行执行也可以并行执行,并行或串行是流的属性。除非是显示要求使用并行流,JDK都是返回的是串行流。串行通过parallel()方法转化为并行。

流的数据源可能是一个可变集合,如果在遍历流时数据源被修改,就会产生干扰。所以在进行流操作时,流的数据源应保持不变,这个条件并不难维持,如果集合只属于当前线程,只要 lambda 表达式不修改流的数据源就可以。

应避免在传递给流方法的lambda产生副作用,在 lambda 表达式里访问可变变量有可能造成数据竞争或是其它意想不到的问题,因为 lambda 在执行时可能会同时运行在多个线程上,因而它们所看到的元素有可能和正常的顺序不一致。

无干扰:1,不要干扰数据源;2,不要干扰其他lambda表达式,当一个lambda在修改某个可变状态而另一个lambda在读取该状态时就会产生这种干扰。

只要满足无干扰性,就可以安全的进行并行操作并得到可预测的结果,即便对线程不安全的集合。

stream方法

forEach():结束操作

void forEach(Consumer<? super E> action)

作用:对集合中每个元素执行action执行的动作。

filter():中间操作

Stream<T> filter(Predicate<? super T> predicate)

作用:返回一个值包含满足predicate条件元素的Stream。

distinct():中间操作

Stream<T> distinct()

作用:返回一个去除重复元素后的Stream

sorted():中间操作

Stream<T> sorted():自然顺序排序;Stream<T> sorted(Comparator<? super T> comparator)自定义比较器排序

map():中间操作

Stream<R> map(Function<? super T,? extends R> mapper)

作用:返回一个返回一个对当前所有元素执行执行mapper之后的结果组成的Stream。转换后元素的个数不会变,但是类型是转换后的类型。

flatMap():中间操作

Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

作用:对每个元素执行mapper指定的操作,并用所有mapper返回的Stream中的元素组成一个新的Stream作为最终返回结果。

参考:

深入理解Java 8 Lambda(类库篇——Streams API,Collectors和并行) | lucida

推荐阅读更多精彩内容