如何“移除”函数适用于ArrayList而迭代使用for-each循环? [英] How "remove" function works for ArrayList while iterating using for-each loop?

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

问题描述

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



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

请任何人都可以这样解释我的工作方式。

  ArrayList< String> list1 = new ArrayList< String>(); 
list1.add(Hello);
list1.add(World);
list1.add(晚上好);

(String s:list1){
// if(s.equals(World)){
list1.remove(1);




$ b $ p $如果我将它改为 list1.remove(2); list1.remove(0); 然后它的工作正常。



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

解决方案

该列表有一个名为 modCount 的变量,意思是修改计数。无论何时调用 remove (或执行其他结构修改),它都会增加 modCount



如果添加或删除元素而不告诉迭代器,则迭代器无法追踪其在列表中的位置。所以作为一个安全检查,在迭代开始时,迭代器会记录 modCount ,并将其保存为 expectedModCount 。当从迭代器中读取每个项目时,迭代器将检查以确保 modCount 仍等于期望值,如果不是,则会抛出异常。



通常,如果列表在迭代过程中被不安全地修改,这将成功引发异常。但是,如果启用 if 语句,在这种情况下是不够的。当你的代码读取World时,该项目被删除,所以列表现在包含 [Hello,Good Evening code>。迭代器仍然在位置1(现在包含Good Evening),当它试图读取下一个元素时,它现在已经到了列表的末尾,所以不需要检查 modCount ,所以没有例外。



请注意 ConcurrentModificationException文档:一般来说,在存在非同步并发修改的情况下,不可能做出任何硬性保证。快速失败的操作尽可能地抛出ConcurrentModificationException。



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

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





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

这样,迭代器就知道列表已经更改,仍然可以正确迭代。 (String s:new ArrayList<>(list1)){
if(s.equals(World )){
list1.remove(...);
}
}

虽然在这种简单的情况下,你甚至不需要这样做;你可以写:

  list1.remove( 世界); 


I have a very basic question.

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.

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

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

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.

解决方案

The list has a variable called modCount, which means "modification count". Whenever you call remove (or perform other structural modifications), it increments the 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.

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.

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."

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");

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

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