java.util.ConcurrentModificationException with iterator

我知道如果会尝试从集合中删除循环通过它的简单循环,我将获得这个异常:.但是我正在使用迭代器,它仍然会生成这个异常。任何想法为什么以及如何解决它?java.util.ConcurrentModificationException

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);
                }
            }
        }
    }

答案 1

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

仅当从迭代器中使用 remove 方法时,才能删除循环访问的列表中的项目。

编辑:

创建迭代器时,它将开始计算应用于集合的修改。如果迭代器检测到某些修改是在未使用其方法(或在同一集合上使用其他迭代器)的情况下进行的,则无法再保证它不会在同一元素上传递两次或跳过一个,因此它会引发此异常

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

列出要删除的项目,然后在完成迭代后将其删除。


答案 2

迭代器 fail-fast 属性会在每次我们尝试获取下一个元素时检查基础集合结构中的任何修改。如果发现任何修改,则会抛出 ConcurrentModificationException。集合类中迭代器的所有实现在设计上都是快速失败的,除了 ConcurrentHashMap 和 CopyOnWriteArrayList 等并发集合类。

来源:谷歌

通过下面写的例子,你会更好地理解:

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)
         */
    }
}