为什么我的示例没有抛出ConcurrentModificationException异常?

5

我按照一个测试ConcurrentModificationException的概念编写了这个例子:

public class Person
{
    String name;
    public Person(String name)
    {
        this.name = name;
    }
}

public static void main(String[] args)
{
    List<Person> l = new ArrayList<Person>();
    l.add(new Person("a"));
    l.add(new Person("b"));
    l.add(new Person("c"));

    int i  = 0;
    for(Person s : l)
    {
        if(s.name.equals("b"))
            l.remove(i);
        i++;
    }

    for(Person s : l)
        System.out.println(s.name);
}

当我执行上述的main方法时,没有抛出ConcurrentModificationException异常,控制台输出以下结果:
a
c

根据我的了解,当在列表的循环中修改列表时,应该抛出ConcurrentModificationException异常。但是为什么在我的示例中没有发生这种情况呢?


2
不能保证对列表进行结构修改会抛出“ConcurrentModificationException”异常。 - aioobe
可能是由于ArrayList的实现细节所致。请阅读https://dev59.com/SGMl5IYBdhLWcg3wZGLo - Armand
1
由于循环在 remove 后立即退出,如果在 "c" 之后添加第4个元素或删除 Person "a" ,则会导致异常。 - Marvin
@Marvin指出了这种行为。 - Naman Gala
1个回答

1

没有任何保证结构修改列表会抛出ConcurrentModificationException异常。

来自文档:

请注意,由于在不同步的并发修改存在的情况下很难做出任何硬性保证,因此无法保证快速失败行为。 快速失败操作尽最大努力抛出ConcurrentModificationException。 因此,编写依赖于此异常以实现正确性的程序是错误的:应仅使用ConcurrentModificationException检测错误。

在这种特殊情况下,你“幸运”(或者“不幸”,这取决于你的看法)。 结构修改不会被注意到,因为循环在执行另一个修改检查之前退出。

有关详细说明,请参阅dup中的答案:


1
我不敢将此视为答案... - Marco13
@Marco13,你是什么意思?能否澄清一下?我的回答表明该行为符合合同。 - aioobe
1
是的,但它没有以任何形式解释“为什么”。诚然,我也希望它会抛出异常。例如,将另一个人添加到列表中,然后它就会抛出异常。为什么在这种特定的设置下不会抛出异常呢?(我正在调查这个问题... 在我看来是个好问题) - Marco13
更新了我的回答。(但需要注意的是,一个正式的回答需要求助于提问者提供使用的运行时实现细节,因为没有这些信息,我们只能查看合同(javadoc)并推测实现。) - aioobe
好的,这确实是一个重复问题,但我即将发布的内容基本上与https://dev59.com/YGUq5IYBdhLWcg3wPd-r#14674151相同(尽管它是针对特定实现的,但“hasNext”不会引发异常但可能以引用列表的*当前*大小的方式实现,这在我看来就是这里的“答案” - 只是我的个人意见,没有冒犯之意) - Marco13
好的,如果你愿意的话可以编辑答案(我已经将其设为社区维基)。 - aioobe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接