Hashmap.keySet()、foreach 和 remove

2022-09-03 18:06:47

我知道使用java的“foreach”从列表中删除通常是一个很大的禁忌,并且应该使用iterator.remove()。但是,如果我循环使用HashMap的keySet(),那么删除()是否安全?喜欢这个:

for(String key : map.keySet()) {
  Node n = map.get(key).optimize();
  if(n == null) {
   map.remove(key);
  } else {
   map.put(key, n);
  }
}

答案 1

编辑:

我没有注意到你并没有真正添加到地图中 - 你只是在更改条目中的值。在这种情况下,pstanton(预编辑1)解决方案几乎是正确的,但是您应该调用迭代器返回的条目,而不是调用 。(这是可能有效的,但我不相信它是保证的 - 而文档指出这将起作用。setValuemap.putmap.putentry.setValue

for (Iterator<Map.Entry<String, Node>> it = map.entrySet().iterator(); 
     it.hasNext();)
{
    Map.Entry<String, Node> entry = it.next();
    Node n = entry.getValue().optimize();
    if(n == null) 
    {
        it.remove();
    }
    else
    {
        entry.setValue(n);
    }
}

(很遗憾没有方法,否则你仍然可以使用增强的for循环语法,使它不那么笨拙。entryremove

旧答案

(我把这个留在这里是为了更一般的情况,你只想进行任意修改。

否 - 您既不应向地图添加,也不应直接从地图中删除。返回的集合是键的视图,而不是快照。HashSet.keySet()

您可以通过迭代器删除,尽管这需要您显式使用迭代器,而不是通过增强的for循环。

一个简单的选项是从原始集合创建新集合:

for (String key : new HashSet<String>(map.keySet())) {
    ...
}

在这一点上,你没问题,因为你没有对集合进行任何更改。

编辑:是的,您绝对可以通过键集迭代器删除元素。从以下文档:HashMap.keySet()

该集合支持元素删除,即通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作从映射中删除相应的映射。它不支持添加或添加全部操作。

这甚至在接口本身中指定。Map


1 我决定编辑我的答案,而不仅仅是评论psanton的答案,因为我认为我为类似但不同的情况获得的额外信息足够有用,值得这个答案留下来。


答案 2

您应该使用条目集:

for(Iterator<Map.Entry<String, Node>> it = map.entrySet().iterator(); it.hasNext();)
{
      Map.Entry<String, Node> entry = it.next();
      Node n = entry.getValue().optimize();
      if(n == null) 
          it.remove();
      else
          entry.setValue(n);
}

编辑固定代码