Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 迭代器应该在源代码修改后何时引发异常?_Java_Arraylist_Iterator - Fatal编程技术网

Java 迭代器应该在源代码修改后何时引发异常?

Java 迭代器应该在源代码修改后何时引发异常?,java,arraylist,iterator,Java,Arraylist,Iterator,在下面的代码段中,将创建ArrayList的迭代器,之后ArrayList的结构将发生变化。然后使用迭代器 ArrayList<Integer> list = new ArrayList<>(2); list.add(1); Iterator<Integer> itr = list.iterator(); list.clear(); list.add(2); list.add(3); while (itr.hasNext()) { System.o

在下面的代码段中,将创建ArrayList的迭代器,之后ArrayList的结构将发生变化。然后使用迭代器

ArrayList<Integer> list = new ArrayList<>(2);
list.add(1);

Iterator<Integer> itr = list.iterator();
list.clear();
list.add(2);
list.add(3);

while (itr.hasNext()) {
    System.out.println(itr.next());
}
几秒钟后,执行毫无例外地完成,结果如下:

2
3
ArrayList在结构上发生了变化,其最终状态与第一个代码段相同,但仍然没有引发异常,即使在第一个代码段中引发了异常

在查看ArrayList源代码后,这是意料之中的,因为底层modCount的类型为int。对ArrayList进行足够的修改会导致modCount溢出,在某些情况下会返回1。迭代器认为ArrayList是不变的,不会引发异常

在Java SE 12文档中,ArrayList类声明:

请注意,无法保证迭代器的快速失效行为,因为一般来说,在存在非同步并发修改的情况下,不可能做出任何硬保证

很明显,迭代器可能会出错,但这同样适用于非同步并发修改,对吗?但是,上面的第二个片段是同步的

这里发生了什么?第二个代码段中的迭代器应该是这样的吗?如果是这样,那么long类型的modCount不是更好一点吗?问题不会消失,但是2^64+1修改在合理的时间内是不可行的


这也可以在其他使用相同int-modCount机制的集合中观察到。

下一句:

快速失败迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测bug

你很幸运,或者说,你正在构建一个非常精确的情况,在这个情况下,你的代码不会抛出CME


我不会对前一句关于非同步并发修改的强调读太多。一种迂腐的解读是,因为一件事可能发生,而且它打破了保证,保证从整体上被打破,因此,担保可能以其他方式被破坏并不重要。

您所做的一切都是创建一个场景,在该场景中,modCount最终将结束,直到它处于某种状态,以反映没有发生修改,因此没有CME。也许您希望modCount是一个long而不是int。

在仔细考虑之后,我得出结论:

如果迭代器抛出ConcurrentModificationException,则源代码在正在进行的迭代中被结构性修改。 如果源代码在结构上被修改,而它的迭代器正在进行迭代,那么迭代器可能抛出ConcurrentModificationException,也可能不抛出ConcurrentModificationException。 考虑到这一点,迭代器尝试抛出ConcurrentModificationException的唯一原因是帮助调试。总比没有好,尤其是在一般情况下


在modCount中使用long而不是int将增加5月的几率,并减少2月的5月不在的几率。但是,只有当一个类型可以容纳无限多个数字时,我们才能使可能的概率为1.0,当然,至少在该体系结构中,可能不会有0.0的概率。因此,无论modCount使用多少个有限位数,它都不会产生渐近效果。

因此,您的问题基本上是:当我创建了一个合成案例来生成modCount时,为什么迭代器无法抛出异常,这将诱使迭代器认为没有任何更改。这是一个好把戏,但有点假问题。在实际用例中,这种情况不太可能发生,但仍然有可能发生。您还可以使用反射来调整列表和迭代器中的modCount。这样代码也不会抛出CME,但它离可用/生产代码很远。你们几乎总是可以骗过课堂,但你们实际上什么也得不到,假问题到底应该是什么?当然是合成的,这是测试软件的一种方法。鉴于modCount是一种尽力而为的修改检查,并且这种情况不太可能在真实代码中发生。在创建迭代器和迭代器在真实代码中进行检查之间不太可能发生2^32次修改,这是一种虚假情况。我知道Javadoc,我想知道的是,迭代器是否只允许在非同步修改时出错,或者仍然允许这样的情况,即使是在同步修改中。
2
3