java8学习之Stream深度解析与源码实践
继续对流进行学习,首先先说明一下流的特点:
1、Collection提供了新的stream()方法。
2、流不存储,通过管道的方式获取值。
3、本质是函数式的,对流的操作会生成一个结果,不过并不会修改底层的数据源,集合可以作为流的底层数据源。
其中需要注意标红的说明,也就是说对于流操作它的源数据是不会被更改的,另外还有一点需要有一个认知:对于一个流可能有若干个中间操作,对于这些操作并非降低了整体的执行性能,反而会有提升,比如说增加了三个中间操作,可能感受会有三次循环,但是实际并非是咱们想象的这样,这个随着流的不断深入就会体会到这点的。
4、延迟查找,很多流操作(过滤filter、映射map、排序sort等)都可以延迟实现。
接着再用代码来进行操练,首先构建一个Stream对象,这里用一个集合的方式构建,然后将它转换数组,如下:
下面具体看一下该方法的定义:
而IntFunction的接口原型如下:
那这个参数如何写呢?当然可以用Lambda表达式啦,那具体如何表示呢?看下面:
其实对于这个toArray()参数还可以改用方法引用,那如何写呢?
接下来想办法将Stream转换为一个List,如何搞呢?
所以转换如下:
初略查看一下上面用到的Collectors类,发现其实它是Java1.8针对集合提供的一个工具类,里面包含若干个实现的工具方法,如下:
那看一下用到的toList()方法的实现:
而回到Stream.collect()方法,它还有另外一个比较复杂的方法重载,如下:
点进去查看一下该方法的定义:
是不是跟第一个collect()方法中使用的Collectors.toList()方法的具体实现中CollectorImpl中的参数一样?既然用stream.collect(Collectors.toList())能达到转换成List的目的,还研究第二种比较复杂重载的stream.collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner)干嘛呢?因为要想搞清楚stream.collect(Collectors.toList())就必须理解这种比较复杂的collect(),因为Collectors.toList()最终的实现就是跟比较复杂的collect()的实现类似,所以说接下来好好理解一下这个比较复杂的方法,确实是不太好理解,先读下它的javadoc:
那什么叫"mutable reduction可变的汇聚"呢?接着看解释:
不晓得说的是什么意思,下面有个例子对其进行说明:
那如何调用这种复杂的collect()方法来实现stream.collect(Collectors.toList())同样的效果呢?实现过程会要复杂很多,但是这个复杂的过程是对其内部了解起到很大的作用,所以有必要折腾一下:
首先第一个参数传递的它:
而Supplier接口的原型是:
因为这个参数是作为最终方法的结果,所以很显然最终应该返回一个ArrayList,所以传参可以这么搞:
接着再来传第二个参数,看下它的原型:
那什么叫累加器呢?在方法注释上也可以看出:
而BiConsumer的接口原型如下:
那这个参数可以这样来传:
还有最后一个参数,它也是BiFunction类型的,如下:
这里先直接上代码,之后再来理解它:
那对于第三个参数的合并器如何来理解呢?其实就是将上一次添的加结果集最终合并到要返回的结果集当中,其中theList1则为要返回的结果集,theList2为上一次累加的结果集,比较难以理解。
其实对于上面的实现还可以用方法引用的方式来代替,这里打算改用LinkedList再改用方法引用去弄,传第一个参数既要返回的结果:
接着传第二个累加器参数,需要接收两个参数,无返回值,这时可以看一下LinkedList.add()方法,如下:
所以第二个参数可以这样写:
接着第三个参数,由于跟第二个参数类型一样,类似的对于LinkedList中有一个addAll方法:
依然可以用方法引用嘛,如下:
好了,接下来再回过头来继续读一下collect()方法:
接下来看一下参数的说明:
再结合咱们的代码来说:
接着再回到stream.collection(Collectors.toList())这个简单的重载方法,看一下它系统的实现:
所以虽然复杂的这个重载方法理解起来比较麻烦,但是这个麻烦是值得滴,另外还有一个原因,因为stream.collection(Collectors.toList())只返回的是一个ArrayList,如果想要返回其它类型的集合如咱们已经实现的LinkedList,那就必须理解复杂的collect()。