在使用for-each循环迭代时,"remove"函数如何为ArrayList工作?

Bra*_*raj 2 java foreach arraylist

我有一个非常基本的问题.

我创建简单ArrayList,我正在使用for-each循环迭代时删除项目.它给了我,java.util.ConcurrentModificationException因为我不能在迭代if删除一个项目,但是当我取消注释条件时它工作正常.

请任何人都能解释我这样做的方式.

    ArrayList<String> list1 = new ArrayList<String>();
    list1.add("Hello");
    list1.add("World");
    list1.add("Good Evening");

    for (String s : list1) {
        //if (s.equals("World")) {
            list1.remove(1);
        //}
    }
Run Code Online (Sandbox Code Playgroud)

如果我将其更改为list1.remove(2);或者list1.remove(0);其工作正常.

注意:这是示例代码,我知道它可以正常使用Iterator.这个问题的唯一目的是知道remove()如果条件未被注释,无论您从列表中删除什么索引,方法如何完美地工作.

Boa*_*ann 5

该列表有一个名为的变量modCount,意思是"修改计数".无论何时你打电话remove(或进行其他结构修改),它都会增加modCount.

如果要在不告知迭代器的情况下添加或删除元素,迭代器无法跟踪其在列表中的位置.因此,作为安全检查,在迭代开始时,迭代器会记录modCount,将其保存为expectedModCount.当从迭代器中读取每个项时,迭代器检查以确保modCount仍然等于期望值,如果不是则抛出异常.

通常,如果在迭代期间不安全地修改列表,这将成功导致抛出异常.但是,在if启用该语句时,这种情况还不够.您的代码读完后"World",该项目将被删除,因此列表现在包含["Hello", Good Evening"].迭代器仍处于位置1(现在包含"Good Evening"),当它尝试读取下一个项目时,它发现它现在已经到达列表的末尾,因此它不会检查modCount.因此,也不例外.

请注意ConcurrentModificationException文档中的警告:"一般来说,在存在非同步并发修改的情况下,不可能做出任何硬性保证.失败快速操作会尽最大努力抛出ConcurrentModificationException."

即使在这种情况下不会抛出异常,代码仍然是错误的.要在迭代时删除元素,必须使用迭代器自己的remove方法:

for (Iterator<String> it = list1.iterator(); it.hasNext();) {
    String s = it.next();
    if (s.equals("World")) {
        it.remove();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,迭代器知道列表已经改变并且仍然可以正确迭代.

或者,您可以从列表的临时副本进行迭代:

for (String s : new ArrayList<>(list1)) {
    if (s.equals("World")) {
        list1.remove(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然在这个简单的例子中,你甚至不需要这样做; 你可以写:

list1.remove("World");
Run Code Online (Sandbox Code Playgroud)