【发布时间】:2019-10-28 17:11:26
【问题描述】:
我知道这绝不应该在生产中发生,但我试图了解有关 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 个元素等时将被拆分。pp。到目前为止一切顺利。
我不明白的是:
(片段 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 位)上运行 sn-ps。
【问题讨论】:
标签: java spliterator