Java 8 ストリーム: limit() と skip() の違い 質問する

Java 8 ストリーム: limit() と skip() の違い 質問する

sについて言えばStream、このコードを実行すると

public class Main {
    public static void main(String[] args) {
        Stream.of(1,2,3,4,5,6,7,8,9)
        .peek(x->System.out.print("\nA"+x))
        .limit(3)
        .peek(x->System.out.print("B"+x))
        .forEach(x->System.out.print("C"+x));
    }
}

この出力が得られます

A1B1C1
A2B2C2
A3B3C3

ストリームを最初の3つのコンポーネントに限定すると、アクションが強制されるからですBそして処刑は3回のみ。

最後の3つの要素に対して同様の計算をskip()メソッドを使用して実行しようとすると、異なる動作が示されます。

public class Main {
    public static void main(String[] args) {
        Stream.of(1,2,3,4,5,6,7,8,9)
        .peek(x->System.out.print("\nA"+x))
        .skip(6)
        .peek(x->System.out.print("B"+x))
        .forEach(x->System.out.print("C"+x));
    }
}

これを出力します

A1
A2
A3
A4
A5
A6
A7B7C7
A8B8C8
A9B9C9

この場合、なぜ行動がA1A6処刑されているのでしょうか?それは、制限短絡ステートフル中間操作、 その間スキップ違いますが、このプロパティの実用的な意味がわかりません。単に「すべてのアクションはスキップ誰もが前に実行されていない制限は"?

ベストアンサー1

ここには 2 つのストリーム パイプラインがあります。

これらのストリーム パイプラインはそれぞれ、ソース、いくつかの中間操作、およびターミナル操作で構成されます。

しかし、中間操作は遅延します。つまり、下流の操作でアイテムが必要にならない限り、何も起こりません。アイテムが必要になった場合、中間操作は必要なアイテムを生成するために必要なすべての処理を実行し、その後、別のアイテムが要求されるまで再び待機します。

ターミナル操作は通常「積極的」です。つまり、完了するために必要なストリーム内のすべての項目を要求します。

forEachしたがって、パイプラインは、背後のストリームに対して次の項目を要求し、そのストリームがさらに背後のストリームに対して要求する、というように、ソースに至るまで繰り返されるものと考えるべきです。

それを念頭に置いて、最初のパイプラインで何が得られるかを見てみましょう。

Stream.of(1,2,3,4,5,6,7,8,9)
        .peek(x->System.out.print("\nA"+x))
        .limit(3)
        .peek(x->System.out.print("B"+x))
        .forEach(x->System.out.print("C"+x));

つまり、 はforEach最初の項目を要求しています。つまり、「B」にはpeek項目が必要であり、limit出力ストリームにそれを要求します。つまり、 はlimit「A」に要求する必要がありpeek、それがソースに送られます。項目が与えられ、 まで進みforEach、最初の行を取得します。

A1B1C1

forEach別のアイテムを要求し、そのたびに別のアイテムを要求します。そして、そのたびに、要求はストリームに伝播され、実行されます。しかし、 がforEach4 番目のアイテムを要求する場合、その要求が に到達したときにlimit、 は、提供可能なすべてのアイテムをすでに提供したことを認識します。

したがって、"A" ピークに別のアイテムを要求しているわけではありません。アイテムが使い果たされたことを直ちに示し、それ以上のアクションは実行されずにforEach終了します。

2 番目のパイプラインでは何が起こりますか?

    Stream.of(1,2,3,4,5,6,7,8,9)
    .peek(x->System.out.print("\nA"+x))
    .skip(6)
    .peek(x->System.out.print("B"+x))
    .forEach(x->System.out.print("C"+x));

再び、forEachは最初のアイテムを要求しています。これは伝播されます。しかし、 に到達するとskip、下流に 1 つ渡す前に上流から 6 つのアイテムを要求する必要があることがわかっています。そのため、"A" から上流に要求を行いpeek、下流に渡さずに消費し、別の要求を行う、というように繰り返します。したがって、"A" ピークはアイテムの要求を 6 回受け取り、6 つのプリントを生成しますが、これらのアイテムは下流に渡されません。

A1
A2
A3
A4
A5
A6

による 7 番目のリクエストではskip、アイテムが「B」ピークに渡され、そこから に渡されるforEachため、完全な印刷が行われます。

A7B7C7

その後は、以前と同じです。skipリクエストを受け取るたびに、スキップジョブがすでに完了していることを「認識」しているため、上流でアイテムを要求し、下流に渡します。そのため、ソースが使い果たされるまで、残りの印刷はパイプ全体を通過します。

おすすめ記事