2

これが本番環境で発生することは決してないことはわかっていますが、Spliterators に関するいくつかの複雑な詳細を理解しようとしており、次の「パズル」に出くわしました (少なくとも私にとってはパズルです)。

(スニペット 1)

List<Integer> list = new ArrayList<>() {{ add(1); add(2); add(3); add(4); }};
Spliterator<Integer> spl1 = list.spliterator();
list.add(5);
list.add(6);
Spliterator<Integer> spl2 = s1.trySplit();
s1.forEachRemaining(System.out::print);
s2.forEachRemaining(System.out::print);

このコードは456123、期待どおりに出力します (私はすでに a を期待していましたが、ConcurrentModificationExceptionの動作を理解しています)。つまり、リストに Spliterator を作成し、リストに 6 つの要素がある場合に分割されます。 .

私が理解していないのは次のとおりです。

(スニペット 2)

List<Integer> list = new ArrayList<>() {{ add(1); add(2); add(3); add(4); }};
Spliterator<Integer> spl1 = list.spliterator();
Spliterator<Integer> spl2 = s1.trySplit();
list.add(5);
list.add(6);
s1.forEachRemaining(System.out::print);
s2.forEachRemaining(System.out::print);

私はこのコードが失敗することを期待してConcurrentModificationExceptionいます. に変更された場合、値とがこのそれぞれの順序で例外の前に配置されていることがわかります。s1.forEachRemaining34System.err::println34PrintStream

今クレイジーな部分:

(スニペット 3)

List<Integer> list = new ArrayList<>() {{ add(1); add(2); add(3); add(4); }};
Spliterator<Integer> spl1 = list.spliterator();
Spliterator<Integer> spl2 = s1.trySplit();
list.add(5);
list.add(6);
s2.forEachRemaining(System.out::print);
s1.forEachRemaining(System.out::print);

s1スニペット 2 と 3 の間の唯一の変更点は、およびにアクセスする順序であることに注意してくださいs2。スニペット 3 はまだ aConcurrentModificationExceptionで失敗しますが、出力される値は12です。これは、s2.forEachRemaining!の行で例外が発生したためです。

私が正しく理解していれば、何が起こるか:

  • Spliterator が初期化される
  • 分割が完了しました
  • 反復が起こる
    • 反復中に、最後の分割が行われたに、基礎となるコレクションに変更があったことが観察されます

これは、Spliterator も Streams と同様に「怠惰」であることを意味しますか? ただし、この議論は、複数の分割を実験する場合、つまり、

(スニペット 4)

List<Integer> list = new ArrayList<>() {{ add(1); add(2); add(3); add(4); add(5); add(6); add(7); add(8); add(9); add(10); }};
Spliterator<Integer> s1 = list.spliterator();
Spliterator<Integer> s2 = s1.trySplit();
list.add(11);
list.add(12);
Spliterator<Integer> s3 = s2.trySplit();
s1.forEachRemaining(s -> System.err.println("1 " + s));
s2.forEachRemaining(s -> System.err.println("2 " + s));
s3.forEachRemaining(s -> System.err.println("3 " + s));

s1その後、問題なく評価され、 の処理中に例外がスローされるはずですが、 !s2の処理中に既に例外がスローされます。s1

ヘルプやポインタをいただければ幸いです。

詳細: 問題があれば、Eclipse 2019-06 (4.12.0) の Windows で AdoptOpenJDK 11.0.4+11 (64 ビット) でスニペットを実行します。

4

1 に答える 1