On stream-lazy-computation
-
Upload
mikeneck-mochida -
Category
Technology
-
view
945 -
download
0
Transcript of On stream-lazy-computation
ことわりこの話を聞いてもアプリ作るのが爆速になるわけではありません
この話を聞いてもアプリが簡単に作れるようになるわけでもありません
この話を聞いても作るアプリケーションが安全になるわけでもありません
単なる知的好奇心を満たすかもしれませんが、儂が満足したいだけです
遅延評価の話はしませんよ
誰?持田真哉(@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パイプラインがやっていること
AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>とは?
Stream<P_OUT>の実装クラス
これをさらに継承したクラスにReferencePipeline<P_IN, P_OUT>という抽象クラスがある(ほぼこれが実体)
さらにStatelessOp<P_IN, P_OUT>、StatefullOp<P_IN, P_OUT>という抽象クラスがある
これらのパイプラインを構成するオブジェクトはデータ構造的に双方向リンクドリストとなって前後のオブジェクトをたどることができる
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の無名クラスの中に埋め込む形で処理を保持する
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<T>という抽象クラスで、リンクドリストの構造を持つ
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の合成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
・begin(long)は次の処理(Sink)のbegin(long)を呼び出す
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
・end()は次の処理(Sink)の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がリンクドリストになっていることで処理順を保持している
ChainedReference<?, A> implements
Sink<A>
Sink<?>
begin(long) begin(long)
accept(a) accept(?)
end() end()a -> b
ChainedReference<?, A> implements
Sink<A>
Sink<?>
begin(long) begin(long)
accept(a) accept(?)
end() end()a -> b
一番最後にあるSinkは何もの?
終端操作と処理開始
一番最後にあるSinkは終端操作で生成されるTerminalOp<T, R>にて生成されるTerminalSink<T, R>
シグニチャーはTerminalSink<T, R> extends Sink<T>, Supplier<R>
終端操作と処理開始TerminalSink<T, R>を生成
パイプラインのリンクをたどりながら各パイプラインのSink opWrapSink(int, Sink)を呼び出してすべての処理を合成したSinkを取得する
合成Sinkのbeginを呼び出す
すべてのソース(Spliterator)にSinkを渡してacceptを呼び出させる
ソースが全てを消費あるいは、必要な結果が得られたら合成Sinkのendを呼び出す
終端操作と処理開始TerminalSink<T, R>を生成
パイプラインのリンクをたどりながら各パイプラインのSink opWrapSink(int, Sink)を呼び出してすべての処理を合成したSinkを取得する
合成Sinkのbeginを呼び出す
すべてのソース(Spliterator)にSinkを渡してacceptを呼び出させる
ソースが全てを消費あるいは、必要な結果が得られたら合成Sinkのendを呼び出す
終端操作呼び出しによってパイプラインをさかのぼって処理(Sink)を構築
SpliteratorにSinkを渡して処理を実行処理終了を処理に通知
まとめストリームパイプラインは双方向リンクドリストを形成するのみで、処理の実行は行わない
処理をリンクドリストで構築することによって処理順序を保証
終端操作でパイプラインを遡って処理を合成、ソースを順次適用