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

时间:2010-11-28 22:38:57

标签: java collections

我想通过应用条件从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
    }
}

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

5 个答案:

答案 0 :(得分:13)

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

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:1)

是 - itr.remove()

  

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

Iterator的{​​{1}}扩展了keySet(),其HashIterator方法调用remove()

如果你需要密钥和值,你也可以获得HashMap.this.removeEntryForKey(key); - 它的迭代器具有相同的属性。

答案 4 :(得分:0)

要做你所描述的,我个人喜欢使用功能样式编程:

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

代码段使用google集合库。它通过仅获取与提供的谓词匹配的那些条目来创建原始地图的视图。