java 从 HashMap 中删除时,为什么会出现 ConcurentModificationException?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4299538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 05:44:58  来源:igfitidea点击:

Why do I get a ConcurentModificationException when removing from a HashMap?

javacollections

提问by Mavin

I want to remove an item from HashMap, by applying a criteria. Consider this code:

我想通过应用条件从 HashMap 中删除一个项目。考虑这个代码:

Set<Foo> set = myMap.keySet();
Iterator<Foo> itr = set.iterator();
while (itr.hasNext())
{
    Foo foo = itr.next();
    if (foo.toString().length() < 3) {
        myMap.remove(foo); //remove the pair if key length is less than 3
    }
}

So I get a ConcurentModificationException because during the iteration I am modifying the HashMap. What should I do? Is there any other way to search for my criteria and execute the remove command at the end so that I can avoid this exception?

所以我得到一个 ConcurentModificationException 因为在迭代期间我正在修改 HashMap。我该怎么办?有没有其他方法可以搜索我的条件并在最后执行 remove 命令,以便我可以避免此异常?

回答by a_horse_with_no_name

Use itr.remove()instead of myMap.remove(o.toString())

使用itr.remove()代替myMap.remove(o.toString())

回答by Jeffrey Bosboom

As of Java 8, Collection provides removeIf(Predicate<? super E>), which will remove all elements for which the given predicate returns true. The example in the question could be rewritten as

从 Java 8 开始,Collection 提供removeIf(Predicate<? super E>),它将删除给定谓词返回 true 的所有元素。问题中的例子可以改写为

myMap.keySet().removeIf(o -> o.toString().length() < 3);

The default implementation provided by Collection uses an iterator and calls Iterator.remove, but collections can override this if they can provide better implementations. More importantly, code using removeIfis clearer and more concise.

Collection 提供的默认实现使用迭代器并调用Iterator.remove,但是如果集合可以提供更好的实现,它们可以覆盖它。更重要的是,代码使用removeIf更加清晰简洁。

回答by AlexR

If you are removing element during iteration you have to use Iterator.remove() instead. Otherwise the current Iterator object enters inconsistent state that causes the exception. You can use Map.remove(key) when you know key, i.e. when you are not iterating over the same Map.

如果您在迭代期间删除元素,则必须改用 Iterator.remove()。否则当前 Iterator 对象会进入导致异常的不一致状态。当您知道 key 时,您可以使用 Map.remove(key),即当您没有迭代同一个 Map 时。

This rule is correct for all collections (Lists, Sets etc).

此规则适用于所有集合(列表、集合等)。

回答by Bozho

Yes - itr.remove()

是的 - itr.remove()

Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next.

从底层集合中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 时只能调用此方法一次。

The Iteratorof the keySet()extends the HashIterator, whose remove()method calls HashMap.this.removeEntryForKey(key);

IteratorkeySet()扩展HashIterator,其remove()方法调用HashMap.this.removeEntryForKey(key);

You can also obtain the entrySet()if you need both the key and the value - its iterator has the same property.

entrySet()如果您同时需要键和值,您也可以获得- 它的迭代器具有相同的属性。

回答by ytoh

To do what you describe I personally like to use functional style programming:

要按照您的描述进行操作,我个人喜欢使用函数式编程:

Map<String,Object> map = // obtained somehow;

Map<String,Object> filtered = Maps.filterKeys(map, new Predicate() {
    @Override
    public boolean apply(String input) {
        return input.length() < 3;
    }
});

The code snippet uses the google collections library. It creates a view of the original map by taking only those entries which keys match the supplied predicate.

代码片段使用谷歌收藏库。它通过仅获取与提供的谓词匹配的那些条目来创建原始映射的视图。