不可修改集合中的ConcurrentModificationException(并发修改异常)

12

我有下面这段代码,当执行以下语句时出现了ConcurrentModificationException异常:

filterCardsToDevice(getCollection());

代码:

private List<MyClass> filterCardsToDevice(Collection<MyClass> col) {
    final List<MyClass> newList = new ArrayList<MyClass>();

    for (MyClass myObj : col) {
        long id = myObj.getId();
        if (id < 0 || id > 0xFFFFFFFFl) {
            // just a log here
        } else {
            newList.add(myObj);
        }
    }

    return newList;
}

private final Map<Long, MyClass> map = new HashMap<Long, MyClass>();

public Collection<MyClass> getCollection() {
    synchronized (map) {
        return Collections.unmodifiableCollection(map.values());
    }
}

堆栈是:

at java.util.HashMap$HashIterator.nextEntry(HashMap.java:841)                 
at java.util.HashMap$ValueIterator.next(HashMap.java:871)                 
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1010)

对于每一行精确地执行:

for (MyClass myObj : col) {

我不明白为什么会出现这个错误,因为我没有修改列表。


1
这不是重复的问题,这是特别询问不可修改集合。 - Anthony C
2个回答

23

请注意,Collections.unmodifiable*并没有复制集合数据,而只是将原始集合包装在一个特殊的包装器中。因此,如果您修改了原始集合,可能会出现错误。


如果您想创建真正独立的不可修改集合实例:

Collections.unmodifiableCollection(new ArrayList<>(map.values()));

6
当您在迭代`col`时,必须注意在另一个线程中更新`map`。`map#values`和`Collections.unmodifiableCollection`都返回现有数据结构的视图,因此您正在迭代的是`map`的entry set(在堆栈跟踪中可以看到)。请注意保留HTML标记。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接