Java list的.remove方法仅适用于每个循环内部的倒数第二个对象

ami*_*kle 10 java foreach

我看到一种奇怪的行为.

    List<String> li = new ArrayList<>();
    li.add("a");
    li.add("b");
    li.add("c");
    li.add("d");
    li.add("e");
    for(String str:li){
        if(str.equalsIgnoreCase("d")){
            li.remove(str);     //removing second last in list works fine
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试删除列表中的第二个以外的任何其他,我得到ConcurrentModificationException.在阅读"Oracle认证助理Java SE 7程序员学习指南2012"时,我注意到它错误地假设.remove()始终使用删除列表中倒数第二个的示例.

pra*_*nth 13

在列表中,添加或删除被视为修改.在您的情况下,您进行了5次修改(添加).

'for each'循环的工作原理如下,

1.It gets the iterator.
2.Checks for hasNext().
Run Code Online (Sandbox Code Playgroud)
public boolean hasNext() 
{
      return cursor != size(); // cursor is zero initially.
}
Run Code Online (Sandbox Code Playgroud)

3.如果是,请使用next()获取下一个元素.

public E next() 
{
        checkForComodification();
        try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
        } catch (IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
        }
}

final void checkForComodification() 
{
    // Initially modCount = expectedModCount (our case 5)
        if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}
Run Code Online (Sandbox Code Playgroud)

重复步骤2和3,直到hasNext()返回false.

如果我们从列表中删除一个元素,它的大小会减少并且modCount会增加.

如果我们在迭代时删除一个元素,则modCount!= expectedModCount得到满足并抛出ConcurrentModificationException.

但删除倒数第二个对象很奇怪.让我们看看它在你的情况下是如何工作的.

原来,

cursor = 0 size = 5 - > hasNext()成功,next()也成功,无异常.
cursor = 1 size = 5 - > hasNext()成功,next()也成功,无异常.
cursor = 2 size = 5 - > hasNext()成功,next()也成功,无异常.
cursor = 3 size = 5 - > hasNext()成功,next()也成功,无异常.

在你删除'd'的情况下,大小减少到4.

cursor = 4 size = 4 - > hasNext()不成功,跳过next().

在其他情况下,ConcurrentModificationException将作为modCount!= expectedModCount抛出.

在这种情况下,不会进行此检查.

如果在迭代时尝试打印元素,则只打印四个条目.跳过最后一个元素.

希望我说清楚.


anu*_*ava 6

Don List#remove(Object)在这里使用,因为您在for-each循环中访问List中的元素.

而是使用Iterator #remove()从List中删除一个项目:

for(Iterator<String> it=li.iterator(); it.hasNext();) {
    String str = it.next();
    if(str.equalsIgnoreCase("d")) {
        it.remove();     //removing second last in list works fine
    }
}
Run Code Online (Sandbox Code Playgroud)