使用迭代器删除条目时出现 ConcurrentModificationException

ConcurrentModificationException when using iterator to remove entry

我有一段简单的代码循环遍历映射,检查每个条目的条件,如果条件为真,则对条目执行一个方法。之后,该条目将从地图中删除。 要从地图中删除条目,我使用 Iterator 来避免 ConcurrentModificationException

除了我的代码 确实it.remove() 行抛出异常:

Caused by: java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.remove(Unknown Source) ~[?:1.8.0_161]
    at package.Class.method(Class.java:34) ~[Class.class:?]

经过长时间的搜索我找不到解决这个问题的方法,所有答案都建议使用 Iterator.remove() 方法,但我已经在使用它了。 Map.entrySet() 的文档明确指出可以使用 Iterator.remove() 方法从集合中删除元素。

如有任何帮助,我们将不胜感激。

我的代码:

Iterator<Entry<K, V>> it = map.entrySet().iterator();
while (it.hasNext()) {
    Entry<K, V> en = it.next();

    if (en.getValue().shouldRun()) {
        EventQueue.invokeLater(()->updateSomeGui(en.getKey())); //the map is in no way modified in this method
        en.getValue().run();
        it.remove(); //line 34
    }
}

请使用 ConcurrentHashMap 代替 HashMap,因为您在多个线程中对对象进行操作。 HashMap class 不是线程安全的,也不允许这样的操作。请参阅下面link以获取与此相关的更多信息。

https://www.google.co.in/amp/s/www.geeksforgeeks.org/difference-hashmap-concurrenthashmap/amp/

让我知道更多信息。

如果您无法将 HashMap 更改为 ConcurrentHashMap,您可以对代码使用其他方法。

您可以创建一个包含要删除的条目的条目列表,然后遍历它们并将它们从原始映射中删除。

例如

    HashMap<String, String> map = new HashMap<>();
    map.put("1", "a1");
    map.put("2", "a2");
    map.put("3", "a3");
    map.put("4", "a4");
    map.put("5", "a5");
    Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
    List<Map.Entry<String, String>> entries = new ArrayList<>();

    while (iterator.hasNext()) {
        Map.Entry<String, String> next = iterator.next();
        if (next.getKey().equals("2")) {
            /* instead of remove
            iterator.remove();
            */
            entries.add(next);
        }
    }

    for (Map.Entry<String, String> entry: entries) {
        map.remove(entry.getKey());
    }

出于此类目的,您应该使用地图公开的集合视图:

keySet() lets you iterate over keys. That won't help you, as keys are usually immutable.

values() is what you need if you just want to access the map values. If they are mutable objects, you can change directly, no need to put them back into the map.

entrySet() the most powerful version, lets you change an entry's value directly.

示例:将所有包含大写的键的值转换为大写

for(Map.Entry<String, String> entry:map.entrySet()){
    if(entry.getKey().contains("_"))
        entry.setValue(entry.getValue().toUpperCase());
}

实际上,如果您只想编辑值对象,请使用值集合来完成。我假设您的地图类型为 :

for(Object o: map.values()){
    if(o instanceof MyBean){
        ((Mybean)o).doStuff();
    }
}