Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.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 为什么这段代码不抛出ConcurrentModificationException?_Java - Fatal编程技术网

Java 为什么这段代码不抛出ConcurrentModificationException?

Java 为什么这段代码不抛出ConcurrentModificationException?,java,Java,为什么这段代码不抛出ConcurrentModificationException?它在对集合进行迭代时修改集合,而不使用Iterator.remove方法,该方法的作用是 替换为以下实现: public boolean hasNext() { if (cursor != size()) return true; checkForComodification(); return false; } 由于Sun

为什么这段代码不抛出ConcurrentModificationException?它在对集合进行迭代时修改集合,而不使用Iterator.remove方法,该方法的作用是

替换为以下实现:

    public boolean hasNext() {
        if (cursor != size())
            return true;
        checkForComodification();
        return false;
    }
由于Sun内部监管机构拒绝,因此不会进行此更改。正式裁决表明,这一变化已经发生 展示了具有重大兼容性影响的潜力 根据现行守则。兼容性的影响是修复程序已经 将沉默的不当行为替换为 ConcurrentModificationException

一般来说,ConcurrentModificationException是在检测到修改而不是导致修改时抛出的。如果修改后从未访问迭代器,它不会引发异常。不幸的是,这一微小的细节使得ConcurrentModificationException在检测数据结构的误用时相当不可靠,因为它们只是在损坏发生后才抛出的

此场景不会抛出ConcurrentModificationException,因为在修改之后,不会在创建的迭代器上调用next

For each循环实际上是迭代器,因此您的代码实际上如下所示:

List<String> strings = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iter = strings.iterator();
while(iter.hasNext()){
    String string = iter.next();
    if ("B".equals(string))
        strings.remove("B");
}
System.out.println(strings);
考虑在您提供的列表上运行的代码。迭代如下所示:

hasNext返回true,输入loop,->iter移动到索引0,string=A,未删除 hasNext返回true,继续循环->iter移动到索引1,string=B,已删除。字符串现在的长度为2。 hasNext返回false iter当前处于最后一个索引,没有更多的索引要执行,退出循环。 因此,由于ConcurrentModificationException是在对next的调用检测到已进行修改时引发的,因此此场景勉强避免了此类异常

对于你的另外两个结果,我们确实得到了例外。对于A、B、C、D,在删除B之后,我们仍然在循环中,然后检测ConcurrentModificationException,而对于A、B,我可以想象它是某种ArrayIndexOutOfBounds,被捕获并作为ConcurrentModificationException重新抛出,ArrayList的迭代器中的下一个是

public boolean hasNext() {
    return cursor != size;
}
在remove调用之后,迭代器位于索引2,列表的大小为2,因此它报告迭代已完成。没有并发修改检查。对于A、B、C、D或A、B,迭代器不在列表的新端,因此调用next,这将引发异常


ConcurrentModificationExceptions只是一种调试辅助工具。你不能依赖他们。

@Tavian Barnes完全正确。如果所讨论的并发修改未同步,则无法保证引发此异常。引用java.util.ConcurrentModification规范:

请注意,通常不能保证快速失效行为 说起来,在有人在场的情况下,不可能做出任何硬性保证 未同步的并发修改。快速失败操作抛出 ConcurrentModificationException尽最大努力。因此, 编写依赖此异常的程序是错误的 其正确性:ConcurrentModificationException仅应使用 检测错误


因为ConcurrentModificationException是在尽最大努力的基础上抛出的,我喜欢Sun没有做出更改的原因是它可能会让一些坏代码实际开始抛出它应该抛出的异常,但如果他们只是在hasNext而不是next中检查并发修改,那么肯定会抛出异常?这怎么算是最好的努力?@pbabcdefp这是最好的努力,因为如果修改不同步,不能保证JRE会注意到并发的修改。@pbabcdefp:并不意味着我们会像你所想的那样,不断尝试,尽全力去做。这意味着他们会尝试,但他们不会做出承诺。@user2357112是对的,这是一个用词不当的词。这实际上意味着合理的努力,而不是最佳努力。@user2357112supportsMonica-你能在这个相关问题上帮助我吗?谢谢。请注意,原始帖子中的示例代码是一个线程。这里没有同步问题。ConcurrentModificationException中的并发与线程没有直接关系;这仅仅意味着在迭代进行的同时,没有另一个线程修改列表。
List<String> strings = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iter = strings.iterator();
while(iter.hasNext()){
    String string = iter.next();
    if ("B".equals(string))
        strings.remove("B");
}
System.out.println(strings);
public boolean hasNext() {
    return cursor != size;
}