带迭代器的java.util.ConcurrentModificationException

我知道如果试图通过简单的循环从集合中删除循环,我将得到这个exception: java.util.ConcurrentModificationException 。 但我正在使用Iterator,它仍然会产生这个exception。 知道为什么以及如何解决它?

 HashSet tableRecords = new HashSet(); ... for (Iterator iterator = tableRecords.iterator(); iterator.hasNext(); ) { TableRecord record = iterator.next(); if (record.getDependency() == null) { for (Iterator dependencyIt = tableRecords.iterator(); dependencyIt.hasNext(); ) { TableRecord dependency = dependencyIt.next(); //Here is the line which throws this exception if (dependency.getDependency() != null && dependency.getDependency().getId().equals(record.getId())) { iterator.remove(); } } } } 

您必须使用iterator.remove()而不是tableRecords.remove()

只有在使用迭代器中的remove方法时,才能删除迭代列表中的项目。

编辑:

创建迭代器时,它会开始计算对集合应用的修改。 如果迭代器检测到某些修改没有使用它的方法(或在同一个集合上使用另一个迭代器),它就不能再保证它不会在同一个元素上传递两次或跳过一个,所以它抛出了这个exception

这意味着您需要更改代码,以便只通过iterator.remove删除项目(并且只使用一个迭代器)

要么

制作要删除的项目列表,然后在完成迭代后删除它们。

每当我们尝试获取下一个元素时,Iterator fail-fast属性检查底层集合结构中的任何修改。 如果找到任何修改,则抛出ConcurrentModificationException。 除了并发集合类(如ConcurrentHashMap和CopyOnWriteArrayList)之外,Collection类中Iterator的所有实现都是设计失败的。

来源:谷歌

您将通过以下示例更好地理解: –

 import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class IteratorExp { public static void main(String... q) { //CASE - ONE List strList = new ArrayList<>(Arrays.asList("a", "b", "c")); Iterator itr = strList.iterator(); /* * strList.add("e"); strList.add("f"); strList.add("g"); */ while (itr.hasNext()) { System.out.println(itr.next()); } /* * Exception in thread "main" java.util.ConcurrentModificationException * at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at * java.util.ArrayList$Itr.next(Unknown Source) at * IteratorExp.main(IteratorExp.java:14) */ //CASE - TWO List intList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); Iterator itrOne = intList.iterator(); Iterator itrTwo = intList.iterator(); for (; itrOne.hasNext();) { if (itrOne.next().equals(5)) { itrOne.remove(); // #1 //intList.remove(itrOne.next()); // #2 } } for (; itrTwo.hasNext();) { if (itrTwo.next().equals(5)) { itrTwo.remove(); // #1 //intList.remove(itrTwo.next()); // #2 } } /* * Exception in thread "main" java.util.ConcurrentModificationException * at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at * java.util.ArrayList$Itr.next(Unknown Source) at * IteratorExp.main(IteratorExp.java:35) */ } } 

HashSet迭代器的契约是除了通过特定迭代器的remove方法之外,你不能从hashset中删除。 从dependencyIt的角度来看,除了通过调用其remove方法之外,您已经删除了一个项,因此它会抛出ConcurrentModificationException

您似乎希望在具有相同记录ID的记录集中删除记录。 覆盖记录的equalshashcode方法以确保具有相同id的记录具有相同的hashcode并不容易吗? (如果这当然有道理)

问题是你在同一时间在范围内有两个迭代器,它们彼此“战斗”。 解决问题的最简单方法就是在找到匹配项时保释内循环:

 for (Iterator iterator = tableRecords.iterator(); iterator.hasNext(); ) { TableRecord record = iterator.next(); if (record.getDependency() == null) { for (Iterator dependencyIt = tableRecords.iterator(); dependencyIt.hasNext(); ) { TableRecord dependency = dependencyIt.next(); //Here is the line which throws this exception if (dependency.getDependency() != null && dependency.getDependency().getId().equals(record.getId())) { iterator.remove(); break; // ADD THIS LINE } } } } 

只要更改了底层容器而没有使用Iterator进行更改,Java Iterator就会“快速失败”。 您正在使用嵌套迭代器,因此任何发出给它的remove()操作都会导致另一个在继续使用时抛出Exception 。 出于这个原因,如果你需要发出一个remove() ,那么你需要在“外部”迭代器(你正在做)上做它,然后停止使用第二个迭代器(添加的break语句就是这样做的) )。