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

Pau*_*ton 25 java

为什么这段代码没有抛出ConcurrentModificationException?它修改了一段Collection时间迭代它,而不使用Iterator.remove()方法,这是唯一安全的删除方法.

List<String> strings = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String string : strings)
    if ("B".equals(string))
        strings.remove("B");
System.out.println(strings);
Run Code Online (Sandbox Code Playgroud)

如果我ArrayList用a 替换,我会得到相同的结果LinkedList.但是,如果我将列表更改为("A", "B", "C", "D)或只是("A", "B")按预期获得异常.到底是怎么回事?我正在使用,jdk1.8.0_25如果这是相关的.

编辑

我找到了以下链接

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4902078

相关部分是

天真的解决方案是在AbstractList中为hasNext添加编码检查,但这会使编纂检查的成本增加一倍.事实证明,仅在最后一次迭代时进行测试就足够了,这几乎不会增加成本.换句话说,hasNext的当前实现:

    public boolean hasNext() {
        return nextIndex() < size;
    }
Run Code Online (Sandbox Code Playgroud)

被此实现取代:

    public boolean hasNext() {
        if (cursor != size())
            return true;
        checkForComodification();
        return false;
    }
Run Code Online (Sandbox Code Playgroud)

由于Sun内部监管机构拒绝了此项更改,因此不会进行此更改.正式裁决表明,这一变化"已证明可能对现有代码产生重大的兼容性影响." ("兼容性影响"是修复程序有可能用ConcurrentModificationException替换静默不当行为.)

Msh*_*nik 22

作为一般规则,ConcurrentModificationException检测到修改时抛出s ,而不是引起.如果您在修改后从未访问过迭代器,则不会抛出异常.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);
Run Code Online (Sandbox Code Playgroud)

考虑在您提供的列表上运行的代码.迭代看起来像:

  1. hasNext() 返回true,输入循环, - > iter移动到索引0,字符串="A",未删除
  2. hasNext()返回true,继续循环 - > iter移动到索引1,字符串="B",删除.strings现在长度为2.
  3. hasNext() 返回false(iter当前位于最后一个索引,不再有索引),退出循环.

因此,ConcurrentModificationException当在next()检测到已经进行修改的调用时抛出s ,这种情况可以狭隘地避免这种异常.

对于您的其他两个结果,我们会得到例外.因为"A", "B", "C", "D",在删除"B"后我们仍然在循环中,并next()检测到ConcurrentModificationException,而"A", "B"我想象它是某种ArrayIndexOutOfBounds被捕获并重新抛出为ConcurrentModificationException

  • @pbabcdefp:["尽力而为"](http://en.wikipedia.org/wiki/Best-effort_delivery)并不意味着"我们会尽力尝试做我们所有人的力量",就像你一样可能会想.这意味着他们会尝试,但他们不做任何承诺. (6认同)

use*_*ica 9

hasNext 在ArrayList的迭代器中只是

public boolean hasNext() {
    return cursor != size;
}
Run Code Online (Sandbox Code Playgroud)

在之后remove的呼叫,迭代器的索引为2,而列表的大小为2,所以它报告说,迭代完成.没有并发修改检查.使用("A","B","C","D"或("A","B"),迭代器不在列表的新末尾,因此next被调用,并抛出异常.

ConcurrentModificationExceptions只是一个调试辅助工具.你不能依赖它们.


归档时间:

查看次数:

1496 次

最近记录:

8 年 前