Java 列表的 .remove 方法仅适用于每个循环中的倒数第二个对象

标签 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
        }
    }

但是如果我尝试删除列表中倒数第二个以外的任何内容,我会得到 ConcurrentModificationException。在阅读“Oracle Certified Associate Java SE 7 Programmer Study Guide 2012”时引起了我的注意,该指南错误地假设 .remove() 始终适用于删除列表中倒数第二个的示例。

最佳答案

在列表中,添加或删除被视为修改。在你的情况下你做了 5 修改(增加)。

“for each”循环的工作方式如下,

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

3.If true, gets the next element using 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();
}

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

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

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

但是移除倒数第二个对象很奇怪。让我们看看它在您的案例中是如何工作的。

最初,

cursor = 0 size = 5 --> hasNext() succeeds and next() also succeeds without exception.
cursor = 1 size = 5 --> hasNext() succeeds and next() also succeeds without exception.
cursor = 2 size = 5 --> hasNext() succeeds and next() also succeeds without exception.
cursor = 3 size = 5 --> hasNext() succeeds and next() also succeeds without exception.

在您删除“d”的情况下,大小会减小到 4。

cursor = 4 size = 4 --> hasNext() does not succeed and next() is skipped.

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

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

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

希望我说清楚了。

关于Java 列表的 .remove 方法仅适用于每个循环中的倒数第二个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16079931/

相关文章:

java - 为什么 Java 8 Stream 接口(interface)没有 min() 无参数版本?

java - 谁能解释一下这是如何工作的吗?

c++ - 为什么不能 for_each 修改它的仿函数参数?

c++ - std::list 和 std::for_each:我的终点在哪里?

java - 初始 SessionFactory 创建失败。java.lang.NoClassDefFoundError : org/hiber nate/cfg/Configuration

java - 如何使用 Gson 为该 Json 文件设置响应类?

java - 我们可以创建同一个 java(spring) 批处理作业的多个实例吗?

java - 如何使用 Maven 将 WAR 文件部署到 Tomcat?

php - 使用 foreach 将元素数组放在正确的标题下

c++ - 为什么我的并行 std::for_each 只使用 1 个线程?