8534


Java の Stream において、pipeline を途中で止める方法を探しています。

例えば以下のようにすると、

[code]

    IntStream stream = IntStream.of(1, 2, 3);
    stream.peek(i -> System.out.println("1st: " + i))
        .peek(i -> System.out.println("2nd: " + i))
        .peek(i -> System.out.println("3rd: " + i))
        .sum();
    
[/code]

結果は以下の通りで、

[code]

    1st: 1
    2nd: 1
    3rd: 1
    1st: 2
    2nd: 2
    3rd: 2
    1st: 3
    2nd: 3
    3rd: 3
    
[/code]

各要素が順に pipeline で処理されているのがわかります。

これを 1st の peek() の後で堰き止め、

[code]

    1st: 1
    1st: 2
    1st: 3
    2nd: 1
    3rd: 1
    2nd: 2
    3rd: 2
    2nd: 3
    3rd: 3
    
[/code]

といった感じにできないかと考えています。

以下のように sorted() を使うとまさにその通りの結果が得られるのですが、  
sort はコストが高そうで使いたくありません。

[code]

    IntStream stream = IntStream.of(1, 2, 3);
    stream.peek(i -> System.out.println("1st: " + i))
        .sorted()
        .peek(i -> System.out.println("2nd: " + i))
        .peek(i -> System.out.println("3rd: " + i))
        .sum();
    
[/code]

用途としては、前半で全要素から得た結果を後半で使いたいと思っています。

何か良い手はないでしょうか。


CC BY-SA 3.0
2015-03-28T07:11:45.153
8505
2015-03-31T05:15:20.057
2015-03-29T22:19:08.713
46
5288
question
java java8 stream
Java の Stream において pipeline を途中で止める方法


そもそも、[`peek()`中間操作](https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html#peek-
java.util.function.Consumer-)は主にデバッグ用途（中間値の確認）として提供されるものです。Stream処理ロジックの一部として使うことは推奨されません。ストリーム処理中の[副作用に関する注意](https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/package-
summary.html)も確認してください。

また`sorted()`中間操作による堰き止めに頼るのもお勧めできません。例示コードでは、ソート処理には全要素値バッファリングが必要なので、結果的に期待する動作となっています。しかしSpliteratorが[`SORTED`特性](http://docs.oracle.com/javase/jp/8/docs/api/java/util/Spliterator.html#SORTED)をもつ場合、`sorted()`中間操作は"何もしない"と考えられます。

仰るような動作をさせたければ、単にストリームを2回生成すべきだと思います。（`peek`の使用はあえて残しましたが、本来は全体処理を見直すべきです。）

[code]

    IntStream stream = IntStream.of(1, 2, 3);
    stream.forEach(i -> System.out.println("1st: " + i))
    
    stream = IntStream.of(1, 2, 3);
    stream.peek(i -> System.out.println("2nd: " + i))
        .peek(i -> System.out.println("3rd: " + i))
        .sum();
    
[/code]

* * *

> 用途としては、前半で全要素から得た結果を後半で使いたいと思っています。

一応、堰き止めたいタイミングで配列へ変換(`toArray()`)し、新たにストリームを生成する方法があります。ただし、中間操作の処理順序に依存すること自体がStream処理にそぐわないため、"堰き止め"ても処理が非効率になるだけですね。

[code]

    IntStream stream = IntStream.of(1, 2, 3);
    IntStream.of(
        stream
          .map(x -> x * 2)
          .peek(i -> System.out.println("1st: " + i))  // for DEBUG
          .toArray()
      )
      .peek(i -> System.out.println("2nd: " + i))  // for DEBUG
      .peek(i -> System.out.println("3rd: " + i))  // for DEBUG
      .sum();
    
[/code]


CC BY-SA 3.0
2015-03-29T14:07:44.163
8534
2015-03-31T05:15:20.057
2015-03-31T05:15:20.057
49
49
8505
answer