Java并发修改exception错误
我正在玩我的大学课程的一些代码,并改变了方法
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); }
但是新方法不断给出并发修改错误。 我怎样才能解决这个问题,为什么会这样呢?
这是因为您在执行remove()
后继续遍历列表。
你正在同时读取和写入列表,这打破了foreach循环下的迭代器的契约。
使用Iterator.remove()
for(Iterator iter = students.iterator(); iter.hasNext(); ) { Student student = iter.next(); if(studentName.equalsIgnoreCase(student.getName()) { iter.remove(); } }
它描述如下:
返回迭代中的下一个元素。
如果迭代没有更多元素,则抛出
NoSuchElementException
。
您可以使用Iterator.hasNext()
来检查是否有可用的下一个元素。
foreach
构造使用底层Iterator
。
在第二种方法中,即使从列表中删除项目,您仍继续迭代。 这导致了您看到的exception。 看一下从ConcurrentModificationException
文档中获取的这个语句:
例如,一个线程通常不允许修改Collection,而另一个线程正在迭代它。 通常,在这些情况下,迭代的结果是不确定的。 如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此exception。
发生此错误的原因是您在迭代时尝试更改集合的大小。 如果你有10个学生,你开始循环期望经历10次迭代。 删除学生时,仍需要进行多少次迭代? 答案显然取决于您从列表中删除学生的位置以及您当前在迭代中的位置。 显然,java无法知道这一点。
要解决这个问题,必须使用迭代器。 您可以按如下方式完成此操作:
Iterator studentsIterator; for(studentsIterator = students.iterator(); studentsIterator.hasNext();) { Student student = studentsIterator.next(); if(student... /* condition */) { studentIterator.remove(); //This removes student from the collection safely } }
在迭代students
集合时,不允许从students
集合中删除元素。
当不允许这样的修改时,检测到对象的并发修改的方法可能抛出此exception。
例如,一个线程通常不允许修改Collection,而另一个线程正在迭代它。 通常,在这些情况下,迭代的结果是不确定的。
http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html
尝试改为
Iterator itr = students.iterator(); while (itr.hasNext()) { Student student = itr.next(); if (studentName.equalsIgnoreCase(student.getName())) { itr.remove(); } }
如果要在循环内部删除,则应使用迭代器及其remove方法
public boolean removeStudent(String studentName) { Iterator itS = students.iterator(); while(itS.hasNext()) { Student student = itS.next(); if (studentName.equalsIgnoreCasee(student.getName())) { itS.remove(); return true; } } return false; }
在使用for-each语句时,不应该从集合中删除对象 – 这将导致exception,因为迭代器在迭代过程中面向更改的集合。 (for循环)使用常规for循环(对于int i = 0; i <100; i ++)等...或者保持要在列表中删除的对象,并将它们移除到for循环之外。
此外,您通过索引删除对象,其中索引为:0,1,2但索引应该通常是学生的索引。
在迭代它时,不允许从集合中删除元素。 迭代器在使用过程中检测到结构更改,并抛出exception。 许多集合都以这种方式实现。
直接使用迭代器:
Iterator it = students.iterator(); while (it.hasNext()) { Student student = it.next(); if (studentName.equalsIgnoreCase(student.getName())) { it.remove(); return true; } } return false;
你可以避免并发修改错误购买只是在删除元素后打破循环或者如果方法有一个返回类型在删除元素后返回一个值。