我知道这绝不应该在生产中发生,但我试图了解有关 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
(咳嗽我已经预料到了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.forEachRemaining
34
System.err::println
3
4
PrintStream
现在疯狂的部分:
(片段 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);
请注意,片段 2 和 3 之间的唯一变化是我们访问s1
和的顺序s2
。代码段 3 仍然失败ConcurrentModificationException
,但打印的值为1
和2
。这是因为异常现在发生在s2.forEachRemaining
!
如果我理解正确,会发生什么:
- Spliterator 已初始化
- 拆分完成
- 迭代发生
- 在迭代期间,观察到在最后一次拆分完成后,基础集合发生了修改
这是否意味着 Spliterators 也像 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 位)上运行代码片段。