简体   繁体   English

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

[英]ConcurrentModificationException when using iterator to remove entry

I have a simple piece of code that loops through a map, checks a condition for each entry, and executes a method on the entry if that condition is true.我有一段简单的代码,它循环遍历地图,检查每个条目的条件,如果条件为真,则在条目上执行一个方法。 After that the entry is removed from the map.之后,条目将从地图中删除。 To delete an entry from the map I use an Iterator to avoid ConcurrentModificationException 's.为了从地图中删除一个条目,我使用了一个Iterator来避免ConcurrentModificationException的。

Except my code does throw an exception, at the it.remove() line:除了我的代码不会抛出异常,在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:?]

After a long search I can't find a way to fix this, all answers suggest using the Iterator.remove() method, but I'm already using it.经过长时间的搜索,我找不到解决此问题的方法,所有答案都建议使用Iterator.remove()方法,但我已经在使用它了。 The documentation for Map.entrySet() clearly specifies that it is possible to remove elements from the set using the Iterator.remove() method. Map.entrySet()的文档明确指出可以使用Iterator.remove()方法从集合中删除元素。

Any help would be greatly appreciated.任何帮助将不胜感激。

My code:我的代码:

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

If you cannot change HashMap to ConcurrentHashMap you can use another approach to your code. 如果您无法将HashMap更改为ConcurrentHashMap ,则可以使用其他方法来编写代码。

You can create a list of entries containing the entries that you want to delete and then iterate over them and remove them from the original map. 您可以创建包含要删除的条目的条目列表,然后迭代它们并从原始映射中删除它们。

eg 例如

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

Please use ConcurrentHashMap in place of HashMap as you are acting on the object in multiple threads. 当您在多个线程中处理对象时,请使用ConcurrentHashMap代替HashMap。 HashMap class isn't thread safe and also doesn't allow such operation. HashMap类不是线程安全的,也不允许这样的操作。 Please refer below link for more information related to this. 有关此问题的更多信息,请参阅以下链接。

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

Let me know for more information. 让我知道更多信息。

For such purposes you should use the collection views a map exposes:为此,您应该使用地图公开的集合视图:

keySet() lets you iterate over keys. keySet() 允许您迭代键。 That won't help you, as keys are usually immutable.这对您没有帮助,因为键通常是不可变的。

values() is what you need if you just want to access the map values.如果您只想访问地图值,则 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. entrySet() 最强大的版本,可以让您直接更改条目的值。

Example: convert the values of all keys that contain an upperscore to uppercase示例:将包含大写的所有键的值转换为大写

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

Actually, if you just want to edit the value objects, do it using the values collection.实际上,如果您只想编辑值对象,请使用 values 集合。 I assume your map is of type <String, Object>:我假设您的地图属于 <String, Object> 类型:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM