Hashmap.keySet(),foreach和remove

时间:2010-01-08 07:29:58

标签: java iterator foreach hashmap

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

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

2 个答案:

答案 0 :(得分:18)

编辑:

我没有注意到你没有真正添加到地图 - 你只是改变了条目中的值。在这种情况下,pstanton(预编辑 1 )解决方案接近,但你应该在迭代器返回的条目上调用setValue,而不是调用map.put。 (可能 map.put将起作用,但我不相信它是有保证的 - 而文档声明entry.setValue 工作。)< / p>

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

(遗憾的是entry没有remove方法,否则你仍然可以使用增强的for循环语法,使其稍微不那么笨重。)

旧答案

(我在这里留下了更常见的情况,你只想进行任意修改。)

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

可以通过迭代器删除,虽然这要求你明确地使用迭代器而不是通过增强的for循环。

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

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

此时你没事,因为你没有对套装做任何改动。

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

  

该集支持删除元素,   删除相应的   从地图映射,通过   Iterator.remove,Set.remove,   removeAll,retainAll和clear   操作。它不支持   添加或添加所有操作。

这甚至在Map界面本身中指定。


1 我决定编辑我的答案,而不仅仅是评论psanton的答案,因为我认为我为类似但不同的情况所获得的额外信息对于值得留下的答案是非常有用的。

答案 1 :(得分:12)

你应该使用条目集:

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

编辑固定代码