您好,登錄后才能下訂單哦!
??Stream把對一個集合的很多操作,以一種流式作業串起來,按照類似函數式編程書寫代碼,界面清爽清晰。
??Stream不同于Guava的FluentIterable系列。FluentIterable系列,是通過封裝集合(List、Set等)并且重載迭代器、get的方式,進行的transform、filter等,優點是簡單并且性能高。缺點是功能單一、并且容易誤用。比如,對transform之后的列表的每個項,本質上都是一個視圖(View),而不是實際的項(值對象)。多次調用get方法。這本質上每次都會層層調用Function的apply方法,如果其中有復雜運算或者I/O讀取,效率是非常低的。
Stream本身,建立了一系列的數據結構,其中的數據都可以看成是實際存在的數據,而并不僅僅是視圖。網上分析源代碼的文章非常多,這里不重復描述,而是僅僅介紹理解的一個思路。
??首先,是幾個關鍵的數據結構。
??Stream。接口是BaseStream,可以看做是流基本『形態』的描述。或者說,每個流式作業。雖然后面提到的Pipeline也是實現了BaseStream,但是這樣似乎更容易理解。
??Pipeline。公共父類是AbstractPipeline。可以看做是流式作業中的每個作業,或者說是每個作業節點。為了防止不必要的裝箱和拆箱操作,又分成了ReferencePipeline、IntPipeline、LongPipeline、DoublePipeline。這些管道可以分成三種:頭、終結操作、非終結操作。分別對應的類是XXXXPipeline.Head、XXXXPipeline.StatelessOp和XXXXPipeline.StatefulOp、TerminalOp.調用流的工作方法,都會制造出來這樣一個Pipeline。比如,調用IntStream.of(),就會生成一個頭;調用Stream.map(),會生成一個非終結操作;調用Stream.reduce(),生成一個終結操作。非終結操作里面,都要實現opWrapSink方法,該方法要返回一個Sink。
??Sink。每個操作,對應一個Sink。每個Sink,關注三個方法:begin、end、accept。如果當前的Sink沒有操作,那么直接調用downstream.accept;否則,把當前操作結果作為參數調用downstream.accept。downstream是什么概念呢?比如,一個流的操作是IntStream.of(1,2,3).map(x -> x + 1).boxed().max()。那么map對應的sink,就是頭的downstream,boxed對應的sink就是map的downstream。綜合起來,只要調用了頭的accept,就會層層調用到最后一個終結操作。終結操作沒有opWrapSink方法,所以自然不會調用到后續的流。
??Spliterator。流里面數據的訪問工具。如果是串行流,一般是直接調用里面的forEachRemaining。該方法里關注action.accept,如果之前串聯好了每個Sink,那么這里一句調用,就開始了Sink的層層調用。
??至此,基本數據結構就介紹這些。下面,關注流的每個節點,是如何連起來的。
??每個Stream,由一組Pipeline節點組成,每追加一個操作,都會向這組Pipeline后面追加一個Pipeline結構。追加時候維護的信息里面,關注sourceStage(頭),previousStage(上一個Pipeline),sourceSupplier(流數據的Spliterator),depth(Pipeline長度)。一直到最后的終結操作,連城一個Pipeline鏈。
??對于終結操作,不論是reduce,還是collect操作,都會調用到AbstracePipeline.evaluate方法。以串行流的reduce為例,直接調用到AbstractPipeline.wrapAndCopyInto。
??其中,wrap是遍歷Pipeline鏈,調用每個階段的opWrapSink。這樣每個Sink通過方法逐層調用(而非內存數據上的指針鏈接),從第一個Pipeline的Sink鏈接到末尾。
@Override
@SuppressWarnings("unchecked")
final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
Objects.requireNonNull(sink);
for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
}
return (Sink<P_IN>) sink;
}
??copyInto是依次調用Sink.begin,Spliterator.forEachRemaing,Sink.end方法。上文曾經提到,forEachRemaing會以流里的每項數據為參數,層層調用每級Sink的accept。
@Override
final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
Objects.requireNonNull(wrappedSink);
if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
wrappedSink.begin(spliterator.getExactSizeIfKnown());
spliterator.forEachRemaining(wrappedSink);
wrappedSink.end();
}
else {
copyIntoWithCancel(wrappedSink, spliterator);
}
}
??至此,整個流的操作,自上而下完全聯系到了一起。
??
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。