私が書いているライブラリの低レベルの操作には、ストリーム スプリッテレータを直接使用しています。tryAdvance/trySplit
最近、ストリーム スプリッターとインターリーブの呼び出しを行ったときに、非常に奇妙な動作を発見しました。問題を示す簡単なコードを次に示します。
import java.util.Arrays;
import java.util.Spliterator;
public class SpliteratorBug {
public static void main(String[] args) {
Integer[][] input = { { 1 }, { 2, 3 }, { 4, 5, 6 }, { 7, 8 }, { 9 } };
Spliterator<Integer> spliterator = Arrays.stream(input).parallel()
.flatMap(Arrays::stream).spliterator();
spliterator.trySplit();
spliterator.tryAdvance(s -> {});
spliterator.trySplit();
spliterator.forEachRemaining(System.out::println);
}
}
出力は
5
6
9
ご覧のとおり、フラット マッピングの後、 から1
までの連続した数字の順序付きストリームを取得する必要があり9
ます。スプリッテレータを 1 回分割したので、中間の場所にジャンプする必要があります。次に、そこから要素を消費し、もう一度分割します。その後、残りの要素をすべて出力します。ストリームの末尾からいくつかの連続した要素があることを期待しています (おそらく要素はゼロですが、それも問題ありません)。しかし、私が得たのは5
and6
で、突然 にジャンプしました9
。
現在、JDK スプリッテレータはこのように使用されていないことを知っています。それらは常にトラバーサルの前に分割されます。ただし、公式ドキュメントtrySplit
では、 afterを呼び出すことを明示的に禁止していませんtryAdvance
。
コレクション、配列、生成されたソースなどから直接作成されたスプリッテレータを使用した場合、問題は発生しませんでした。スプリッテレータが中間を持つ並列ストリームから作成された場合にのみ発生しますflatMap
。
問題は、私がバグに遭遇したのか、それともスプリッテレータをこのように使用することがどこかで明示的に禁止されているのかということです。