如何“删除"函数在使用 for-each 循环进行迭代时适用于 ArrayList? [英] How "remove" function works for ArrayList while iterating using for-each loop?

查看:17
本文介绍了如何“删除"函数在使用 for-each 循环进行迭代时适用于 ArrayList?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a very basic question.

我创建了简单的 ArrayList 并且我在使用 for-each 循环进行迭代时删除了该项目.它给了我 java.util.ConcurrentModificationException 因为我无法在迭代时删除项目但是 当我取消注释 if 条件时它工作正常.

I have created simple ArrayList and I am removing the item while iterating using for-each loop. It gives me java.util.ConcurrentModificationException because I can't remove an item while iterating but when I un-comment the if condition it works fine.

请谁能解释一下 for-each 是如何以这种方式工作的.

Please can anybody explain me how for-each works in this way.

    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);
        //}
    }

如果我将其更改为 list1.remove(2);list1.remove(0); 那么它也可以正常工作.

If I change it to list1.remove(2); or list1.remove(0); then also its working fine.

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

Note: This is sample code and I know it will work fine using Iterator. My sole purpose of this question is to know how method remove() works perfectly if condition is un-commented no matter what index you are removing from the list.

推荐答案

该列表有一个名为 modCount 的变量,意思是修改次数".每当您调用 remove(或执行其他结构修改)时,它都会增加 modCount.

The list has a variable called modCount, which means "modification count". Whenever you call remove (or perform other structural modifications), it increments the modCount.

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

The iterator can't keep track of its position in the list if you are adding or removing elements without telling the iterator. So as a safety check, at the start of iteration, the iterator makes a note of the modCount, saving it as expectedModCount. When each item is read from the iterator, the iterator checks to make sure the modCount still equals the expected value, and throws an exception if it doesn't.

通常,如果在迭代过程中不安全地修改列表,这将成功引发异常.但是,在启用 if 语句的情况下,这还不够.在您的代码读取"World" 后,该项目被删除,因此列表现在包含["Hello", Good Evening"].迭代器仍在位置1(现在包含 "Good Evening"),当它试图读取下一项时,发现它现在已经到达列表的末尾,所以它不会费心去检查modCount.因此,也不例外.

Usually, this will successfully cause the exception to be thrown if the list is unsafely modified during iteration. However, it's not sufficient in this case when the if statement is enabled. After your code has read "World", that item is removed, and so the list now contains ["Hello", Good Evening"]. The iterator is still at position 1 (which now contains "Good Evening") and when it tries to read the next item, it finds it has now reached the end of the list, so it doesn't bother to check the modCount. Hence, no exception.

注意 ConcurrentModificationException 文档中的警告

Note the caveat in the ConcurrentModificationException documentation: "It is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis."

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

Even if it doesn't happen to throw the exception in this case, the code is still wrong. To remove an element while iterating, you must use the iterator's own remove method:

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

这样,迭代器就知道列表发生了变化,仍然可以正确迭代.

That way, the iterator knows that the list has changed and can still iterate correctly.

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

Alternatively, you can iterate from a temporary copy of the list:

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

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

Although, in this simple case, you don't even need to do that; you can just write:

list1.remove("World");

这篇关于如何“删除"函数在使用 for-each 循环进行迭代时适用于 ArrayList?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆