JavaのStreamで学ぶ遅延処理実装パターン
-
Upload
mikeneck-mochida -
Category
Technology
-
view
1.969 -
download
0
Transcript of JavaのStreamで学ぶ遅延処理実装パターン
誰?持田真哉(@mike_neck)
たんなるJava、Groovy好きのおっさん
某IDEを売っている会社に入り浸って、クソコラを作ってる
2015年期待している陸上選手
青山聖佳(400m)、水口怜(走幅跳)、藤光謙司(200m)、高瀬慧(100m)
Streamの復習for文を簡単に今っぽく書くやつ
InputStreamと関係ない(全く関係ないわけでもないけど)
ScalaのStreamとは違う
順次および並列での集約操作をサポートする要素のシーケンス(Javadocより)
Streamの復習repo.findAllUsers().stream()
.filter(User::isMen)
.filter(u -> u.getAge() >= 27)
.filter(u -> u.getAge() <= 35)
.map(User::getHobbies)
.flatMap(List::stream)
.collect(groupingBy(
Hobby::getGenre,
counting()));
ソース
ストリームパイプライン
終端操作
Streamの疑問repo.findAllUsers().stream()
.filter(User::isMen)
.filter(u -> u.getAge() >= 27)
.filter(u -> u.getAge() <= 35)
.map(User::getHobbies)
.flatMap(List::stream)
.collect(groupingBy(
Hobby::getGenre,
counting()));
・これらの処理はどのように保持されるの?・処理の順番はどのように保持されるの?・終端操作呼び出しでどのように処理が実行されるの?
Streamパイプラインがやっていること
repo.findAllUsers().stream()
.filter(User::isMen)
.filter(u -> u.getAge() >= 27)
.filter(u -> u.getAge() <= 35)
.map(User::getHobbies)
.flatMap(List::stream)
.collect(groupingBy(
Hobby::getGenre,
counting()));
・AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>のインスタンスを生成して返す
Streamパイプラインがやっていること
.filter(User::isMen)
.map(User::getHobbies)
AbstractPipeline
AbstractPipeline
User:isMen
User::getHobbies
Streamパイプラインがやっていること
.filter(User::isMen)
.map(User::getHobbies)
.flatMap(List::stream)
AbstractPipeline
AbstractPipeline
AbstractPipeline
User:isMen
User::getHobbies
List::stream
Streamパイプラインがやっていること
.filter(User::isMen)
.map(User::getHobbies)
.flatMap(List::stream)
AbstractPipeline
AbstractPipeline
AbstractPipeline
User:isMen
User::getHobbies
List::stream
AbstractPipelineの逆順リストを作っている
public final <R> Stream map(
Function<? super P_OUT, ? extends R> mapper) {
return
new StatelessOp<P_OUT, R>(this, …) {
@Override Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<P_OUT, R>(sink) {
public void accept(P_OUT u) {downSink.accept(mapper.apply(u));}
}
Streamパイプラインがやっていること
返されるStreamの無名クラスの中のopWrapSinkメソッドに埋め込まれる
public final <R> Stream map(
Function<? super P_OUT, ? extends R> mapper) {
return
new StatelessOp<P_OUT, R>(this, …) {
@Override Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<P_OUT, R>(sink) {
public void accept(P_OUT u) {downSink.accept(mapper.apply(u));}
}
public final <R> Stream map(
Function<? super P_OUT, ? extends R> mapper) {
return
new StatelessOp<P_OUT, R>(this, …) {
@Override Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<P_OUT, R>(sink) {
public void accept(P_OUT u) {downSink.accept(mapper.apply(u));}
}
Sinkの合成
Sinkの合成Sink<T>とは
個々の処理実行・制御を提供するConsumer<T>の拡張インターフェース
初期状態 ! begin(long) ! 処理中 ! accept(T) ! 処理中 ! end() ! 初期状態
後方へのリンクを持つリスト
Sinkの合成ChainedReference<B, A> implements
Sink<A>
ChainedReference<C, B> implements
Sink<B>
begin(long) begin(long)
accept(a) accept(b)
end() end()a -> b b -> c
・先に行われる処理(Sink)は次に行われる処理(Sink)へのリン
クを持っている
Sinkの合成ChainedReference<B, A> implements
Sink<A>
ChainedReference<C, B> implements
Sink<B>
begin(long) begin(long)
accept(a) accept(b)
end() end()a -> b b -> c
・accept(A)は処理を施した後に次の処理(Sink)のaccept(B)を呼び出す
Sinkの合成ChainedReference<B, A> implements
Sink<A>
ChainedReference<C, B> implements
Sink<B>
begin(long) begin(long)
accept(a) accept(b)
end() end()a -> b b -> c
Sinkがリンクドリストになっていることで処理順を保持している
終端操作と処理開始
一番最後にあるSinkは終端操作TerminalOp<T, R>にて生成されるTerminalSink<T, R>
終端操作はAbstractPipelineの逆順リストをたどってSinkを合成していく
終端操作と処理開始AbstractPipeline
AbstractPipeline
AbstractPipeline
Sink
Sink
Sink
TerminalOpTerminalSink
ElementElementElementElement
終端操作と処理開始AbstractPipeline
AbstractPipeline
AbstractPipeline
Sink
Sink
Sink
TerminalOpTerminalSink
ElementElementElementElement
終端操作と処理開始AbstractPipeline
AbstractPipeline
AbstractPipeline
Sink
Sink
Sink
TerminalOpTerminalSink
ElementElementElementElement
まとめストリームパイプラインはStreamを実装した無名クラスのインスタンスの逆順リストを作る
StreamのopWrapSinkに各処理(Function,Predicate)が埋め込まれる
処理順リストによって処理順序を保証
終端操作で逆順Streamインスタンスを遡って処理を合成、ソースを順次適用