2016-11-04 3 views
2

Streamsはストリーム上でterminalメソッドが呼び出されるまで遅延していると理解しています。 私が知っているのは、terminalメソッドが呼ばれた後、すべての中間メソッドが呼び出される順に実行されるということです。Lazy EvaluationとEager EvaluationはJavaでどのように動作するのですか?

しかし、以下のプログラムでは、ストリームがどのように動作しているかを頭に浮かべることはできません。ここにコードがありますが、私は試しました。

import java.util.*; 
import java.util.stream.*; 

class TestEagerLazy 
{ 
    public static void main(String[] args) { 
     ArrayList<Integer> a = new ArrayList<>(); 

     a.add(4);a.add(5);a.add(8); 
     a.add(7);a.add(3);a.add(65); 
     a.add(87);a.add(2);a.add(12); 
     a.add(58);a.add(42); 

     Stream<Integer> st = a.stream().filter(b->{System.out.println("Tested: " + b);return (b%2)==0;}); 

     Spliterator<Integer> it = st.spliterator(); 

     System.out.println("\n\nIterator Results:"); 
     while(it.tryAdvance((j)->System.out.println("iter: "+j))); 


     System.out.println("Last Statement"); 


    } 
} 

次のように私は、ストリームのspliteratorにtryAdvanceを想定して予想される出力は次のようになります。

Iterator Results: 
Tested: 4 
Tested: 5 
Tested: 8 
Tested: 7 
Tested: 3 
Tested: 65 
Tested: 87 
Tested: 2 
Tested: 12 
Tested: 58 
Tested: 42 
iter: 4 
iter: 8 
iter: 2 
iter: 12 
iter: 58 
iter: 42 
Last Statement 

しかし、次のように私が得た出力は:正確なプログラムの流れである

Iterator Results: 
Tested: 4 
iter: 4 
Tested: 5 
Tested: 8 
iter: 8 
Tested: 7 
Tested: 3 
Tested: 65 
Tested: 87 
Tested: 2 
iter: 2 
Tested: 12 
iter: 12 
Tested: 58 
iter: 58 
Tested: 42 
iter: 42 
Last Statement 

何?プログラムはtryAdvanceからストリーム上と後ろをフィルタリングするためにどのように流れますか?

+2

['tryAdvance()'](https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html#tryAdvance-java.util.function.Consumer - )、なぜそう思うのですか? ---全体のポイントは、 "ストリームを1つの要素で進めようとする"ことであり、その上で所定のアクションを実行します。 *一度に1つの要素!* – Andreas

答えて

4

ステートレスストリームは、無限の量の要素を処理するように設計されています。これを可能にするために、ストリームはすべての要素の各操作を一度に評価することはできません。

シーケンシャルストリームは、常にパイプラインを1つずつ実行します。各要素は、次の要素が開始する前にパイプライン全体を通過します。これは、遅延評価を有効にするためのものです。これは、findFirstまたはallMatchなどのように、ストリームを短絡させます。すべての要素が各段階で一度に処理された場合、ストリームはStream.iterateなどの無限のデータソースを処理できません。

あなたのコードの出力は、要素が一度にパイプライン1を通過することを示しています

Iterator Results: 
Tested: 4 // starting 1st element 
iter: 4  // ending 1st element 
Tested: 5 // starting 2nd element (fails the filter) 
Tested: 8 // starting 3rd element 
iter: 8  // ending 3rd element 
Tested: 7 // starting 4th element (fails the filter) 
... 
Last Statement 

これらの行動はJavaDocに、より一般的に説明されています。

+2

[javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#package.description) *怠惰を求める。フィルタリング、マッピング、削除の重複など、多くのストリーム操作を遅延実装することができ、最適化の機会が得られます。例えば、 "3つの連続した母音を持つ最初の' String'を見つける "は、すべての入力文字列を調べる必要はありません。*別の言い方をすれば、' filter() 'メソッドは必要になるまで遅く呼び出されません。これは本当に「怠け者」の定義です。 * – Andreas

+3

@アンドレアス:Streamの実装が他のことをしていることを意味するので、「先延ばし」は適切ではないと思います(Stackoverflowの貢献を書いていますか?)。仕事を始める... – Holger

関連する問題