【问题标题】:Java Concurrent Modification Exception ErrorJava并发修改异常错误
【发布时间】:2013-03-01 08:08:06
【问题描述】:

我正在为我的大学课程玩一些代码,并从

更改了一个方法
public boolean removeStudent(String studentName)
{
    int index = 0;
    for (Student student : students)
    {
        if (studentName.equalsIgnoreCasee(student.getName()))
        {
            students.remove(index);
            return true;
        }
        index++;
    }
    return false;
}

收件人:

public void removeStudent(String studentName) throws StudentNotFoundException
{
    int index = 0;
    for (Student student : students)
    {
        if (studentName.equalsIgnoreCase(student.getName()))
        {
            students.remove(index);
        }
        index++;
    }
    throw new  StudentNotFoundException( "No such student " + studentName);
}

但新方法不断给出并发修改错误。我该如何解决这个问题?为什么会这样?

【问题讨论】:

  • 这是三个被问到最多的 Java 问题之一。您必须使用迭代器并调用 iterator.remove
  • 您在迭代列表时正在更改列表,java 集合不允许这样做。完整的解释可以找到here

标签: java arraylist


【解决方案1】:

这是因为你在执行remove()之后继续遍历列表。

您同时读取和写入列表,这破坏了 foreach 循环底层迭代器的合同。

使用Iterator.remove()

for(Iterator<Student> iter = students.iterator(); iter.hasNext(); ) {
    Student student = iter.next();
    if(studentName.equalsIgnoreCase(student.getName()) {
        iter.remove();
    }
}

描述如下:

返回迭代中的下一个元素。

如果迭代没有更多元素,则抛出 NoSuchElementException

您可以使用Iterator.hasNext() 来检查是否有下一个元素可用。

【讨论】:

    【解决方案2】:

    您可以避免并发修改错误购买只是在删除元素后打破循环,或者如果方法具有返回类型,则在删除元素后返回一个值。

    【讨论】:

    • 谢谢,伙计!这很好用。我不知道为什么没有人对此表示赞同。
    【解决方案3】:

    foreach 构造使用底层Iterator

    在第二种方法中,即使从列表中删除了一个项目,您也会继续迭代。这会导致您看到的异常。看看这个摘自ConcurrentModificationException 文档的声明:

    例如一般不允许一个线程修改 一个集合,而另一个线程正在对其进行迭代。一般来说, 在这些情况下,迭代的结果是不确定的。 一些迭代器的实现(包括所有通用的 JRE 提供的目的集合实现)可以选择 如果检测到此行为,则抛出此异常。

    【讨论】:

      【解决方案4】:

      当你迭代一个元素时,你不能从你的集合中移除它。迭代器在使用过程中检测到结构变化,并抛出异常。许多集合都是以这种方式实现的。

      直接使用迭代器:

          Iterator<Student> it = students.iterator();
          while (it.hasNext()) {
              Student student = it.next();
      
              if (studentName.equalsIgnoreCase(student.getName())) {
                      it.remove();
                      return true;
              }
          }
          return false;
      

      【讨论】:

        【解决方案5】:

        您不应该在使用时从集合中删除对象 for-each 语句 - 这将导致异常,因为您的迭代器在其迭代过程中面临更改的集合。 (for循环) 要么使用常规 for 循环(for int i = 0; i

        此外,您可以按索引删除对象,其中索引为:0、1、2 但 index 实际上应该是学生的索引。

        【讨论】:

          【解决方案6】:

          如果您想在循环中删除,您应该使用迭代器及其remove 方法

          public boolean removeStudent(String studentName)
          {
              Iterator<Student> itS = students.iterator();
              while(itS.hasNext())
              {
                  Student student = itS.next();
                  if (studentName.equalsIgnoreCasee(student.getName()))
                  {
                      itS.remove();
                      return true;
                  }
              }
              return false;
          }
          

          【讨论】:

            【解决方案7】:

            您不能在迭代时从students 集合中删除元素。

            当这种修改是不允许的时,检测到对象的并发修改的方法可能会抛出此异常。

            例如,通常不允许一个线程在另一个线程对其进行迭代时修改 Collection。一般来说,在这些情况下,迭代的结果是不确定的。

            http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html

            尝试更改为

            Iterator<Student> itr = students.iterator();
            while (itr.hasNext()) {
                Student student = itr.next();
                if (studentName.equalsIgnoreCase(student.getName()))
                {
                    itr.remove();
                }
            }
            

            【讨论】:

              【解决方案8】:

              出现此错误是因为您在迭代集合时尝试更改集合的大小。如果你有 10 名学生,你开始你的循环期望经历 10 次迭代。当您删除一个学生时,还需要进行多少次迭代?答案显然取决于您将学生从列表中删除的位置以及您当前在迭代中的位置。显然,java 无法知道这一点。

              要解决这个问题,您必须使用迭代器。您可以按以下方式完成此操作:

              Iterator<Student> studentsIterator;
              for(studentsIterator = students.iterator(); studentsIterator.hasNext();)
              {
                  Student student = studentsIterator.next();
                  if(student... /* condition */)
                  {
                      studentIterator.remove();  //This removes student from the collection safely
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-11-21
                • 1970-01-01
                • 2016-11-19
                相关资源
                最近更新 更多