当前位置: 首页 > 面试题库 >

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

吕冠宇
2023-03-14
问题内容

我看到一个奇怪的行为。

    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认证Java SE 7程序员学习指南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.如果为true,则使用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()成功,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引发。

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

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

希望我说清楚。



 类似资料:
  • 问题内容: 这是Java代码的片段: 它显示5。但是为什么声明了for循环的声明部分,却没有声明? 在uu上,您将引用2D数组…这不是一项作业。我正在准备Java认证。干杯 问题答案: 由于你是一个。因此,当您对其进行迭代时,您将首先获得,然后可以对该数组进行迭代以获取单个元素。 因此,您的外部循环具有as类型,因此具有该声明。如果您在另一个内循环中进行迭代,则将得到以下类型:-

  • 问题内容: 我想为每个循环做一个,但要使其同步运行。循环的每次迭代都将执行http.get调用,并返回json以将值插入数据库中。问题是for循环异步运行,这导致所有http.gets一次全部运行,并且我的数据库最终没有插入所有数据。我正在使用async- foreach尝试执行我想要的操作它可以做到,但是如果我能以正确的方式做到这一点,我就不必使用它。 和我的模特 问题答案: 我发现在完成每个调

  • 考虑这个简单的例子: 此代码将打印,但是,如果我对每个

  • 问题内容: 我有这样的结构: 我想使用内置方法(在一行中)对整数()求和。 有任何想法吗? 问题答案: 会工作。

  • 问题内容: 学生的姓名(String [])和相应的标记(int [])存储在不同的数组中。 如何使用Java中的每个循环一起遍历两个数组? 一种简单的方法是在同一循环中使用索引变量。有什么好办法吗? 问题答案: 潜在的问题实际上是您应该将两个数组绑定在一起,并且仅跨一个数组进行迭代。 这是一个非常简单的演示-您应该使用getter和setter,还应该使用a 而不是数组,但这证明了这一点:

  • 我对Java中枚举类型中的值()方法是如何工作的有点好奇。如Java规范文档中所见,我们可以在a中为每个循环遍历某个枚举类型的所有值。例如。 我认为对于每个循环,迭代所有值。在这个调用中,我们在每个循环调用中重复调用一个方法,那么它将如何迭代所有枚举类型或值()方法使用某种迭代器。有人能帮我记录下这个方法的实现吗?