Java 为什么';这段代码不会抛出ConcurrentModificationException吗?

Java 为什么';这段代码不会抛出ConcurrentModificationException吗?,java,Java,为什么此代码不抛出一个ConcurrentModificationException?它在迭代过程中修改集合,而无需使用迭代器.remove()方法,该方法的作用是: 替换为以下实现: public boolean hasNext() { if (cursor != size()) return true; checkForComodification(); return false; } 由于Sun内部监

为什么此代码不抛出一个
ConcurrentModificationException
?它在迭代过程中修改
集合
,而无需使用
迭代器.remove()
方法,该方法的作用是:

替换为以下实现:

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


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

此场景不会引发
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);
List strings=newarraylist(Arrays.asList(“A”、“B”、“C”));
迭代器iter=strings.Iterator();
while(iter.hasNext()){
String=iter.next();
如果(“B”。等于(字符串))
字符串。删除(“B”);
}
System.out.println(字符串);
考虑在您提供的列表上运行的代码。迭代如下所示:

  • hasNext()
  • hasNext()
    返回true,继续循环->iter移动到索引1,string=“B”,已删除<代码>字符串现在的长度为2
  • hasNext()
  • 因此,当调用
    next()
    检测到已进行修改时,会引发
    ConcurrentModificationException
    s,因此此场景勉强避免了此类异常


    对于你的另外两个结果,我们确实得到了例外。对于
    “A”、“B”、“C”、“D”
    ,在删除“B”之后,我们仍然处于循环中,
    next()
    检测
    ConcurrentModificationException
    ,而对于
    “A”、“B”
    我可以想象它是某种数组索引的边界,被捕获并作为
    ConcurrentModificationException重新抛出

    在数组列表的迭代器中,hasNext
    只是

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


    ConcurrentModificationException
    s只是一种调试辅助工具。您不能依赖它们。

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

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


    因为
    ConcurrentModificationException
    是在“尽力而为”的基础上抛出的,我喜欢Sun没有做出更改的原因是它可能会使一些坏代码实际开始抛出它应该抛出的异常,但如果他们在
    hasNext()中检查并发修改,肯定会抛出异常
    而不是
    next()
    ?这怎么算是“最大努力”?@pbabcdefp这是“最大努力”,因为不能保证如果修改不同步,JRE会注意到并发修改。@pbabcdefp:并不意味着“我们会不断尝试,尽全力去做。”“,就像你可能想的那样。这意味着他们会尝试,但他们不会做出承诺。@user2357112是对的,这是一个用词不当的词。它实际上意味着“合理的努力”,而不是“最佳努力”。@user2357112supportsMonica-你能帮我解决这个相关问题吗?谢谢。请注意,原始帖子中的示例代码是一个线程。这里没有同步问题。
    ConcurrentModificationException
    中的“concurrent”与线程(直接)无关;它只是意味着“在迭代进行的同时”,而不是“另一个线程修改了列表”。
    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;
    }