我知道如果试图通过简单的循环从集合中删除循环,我会得到这个异常:java.util.ConcurrentModificationException
。但我正在使用Iterator,它仍然会产生这个异常。知道为什么以及如何解决它?
HashSet<TableRecord> tableRecords = new HashSet<>();
...
for (Iterator<TableRecord> iterator = tableRecords.iterator(); iterator.hasNext(); ) {
TableRecord record = iterator.next();
if (record.getDependency() == null) {
for (Iterator<TableRecord> 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())) {
tableRecords.remove(record);
}
}
}
}
答案 0 :(得分:35)
您必须使用iterator.remove()
代替tableRecords.remove()
只有在使用迭代器中的remove方法时,才能删除迭代列表中的项目。
编辑:
创建迭代器时,它会开始计算对集合应用的修改。如果迭代器检测到某些修改没有使用它的方法(或在同一个集合上使用另一个迭代器),它就不能再保证它不会在同一个元素上传递两次或跳过一个,所以它抛出了这个异常
这意味着您需要更改代码,以便只通过iterator.remove删除项目(并且只使用一个迭代器)
OR
制作要删除的项目列表,然后在完成迭代后删除它们。
答案 1 :(得分:1)
迭代器故障快速属性检查中的任何修改 每当我们试图获得时,底层集合的结构 下一个元素。如果发现任何修改,它会抛出 ConcurrentModificationException的。 Iterator的所有实现 在Collection类中,除了并发之外,其设计是快速失败的 集合类,如ConcurrentHashMap和CopyOnWriteArrayList。
来源:Google
您最好通过以下示例了解: -
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<String> strList = new ArrayList<>(Arrays.asList("a", "b", "c"));
Iterator<String> 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<Integer> intList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0));
Iterator<Integer> itrOne = intList.iterator();
Iterator<Integer> 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)
*/
}
}
答案 2 :(得分:0)
HashSet迭代器的契约是你不能通过那个特定迭代器的remove方法从hashset中删除。从dependencyIt
的角度来看,除了调用remove
方法之外,您已删除了一个项目,因此它会抛出ConcurrentModificationException
。
似乎您希望在具有相同记录ID的记录集中删除记录。覆盖记录的equals
和hashcode
方法以确保具有相同id的记录具有相同的哈希码并不容易吗? (如果这当然有道理)
答案 3 :(得分:0)
问题是你同时在范围内有两个迭代器,它们彼此“战斗”。解决问题的最简单方法就是在找到匹配项时摆脱内循环:
for (Iterator<TableRecord> iterator = tableRecords.iterator(); iterator.hasNext(); ) {
TableRecord record = iterator.next();
if (record.getDependency() == null) {
for (Iterator<TableRecord> 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
}
}
}
}
Java Iterator
只要在未使用Iterator
进行更改的情况下更改其基础容器,就会“快速失败”。您正在使用嵌套迭代器,因此发布给它的任何remove()
操作都将导致另一个Exception
如果继续使用它。出于这个原因,如果你需要发出remove()
,那么你需要在“外部”迭代器(你正在做)上进行,然后停止使用第二个迭代器(添加{ {1}}声明确实)。