代码之家  ›  专栏  ›  技术社区  ›  Sam Washburn

hashmap.keyset(),foreach和remove

  •  14
  • Sam Washburn  · 技术社区  · 15 年前

    我知道使用Java的“FACHACH”从列表中删除通常是一个很大的不,并且应该使用迭代器。但是,如果循环遍历hashmap的keyset(),删除()是否安全?这样地:

    for(String key : map.keySet()) {
      Node n = map.get(key).optimize();
      if(n == null) {
       map.remove(key);
      } else {
       map.put(key, n);
      }
    }
    
    2 回复  |  直到 15 年前
        1
  •  18
  •   Jon Skeet    15 年前

    编辑:

    我没注意到你不是真的 添加 到地图-您只是更改了条目中的值。在这种情况下,pstanton(预编辑 解决方案是 几乎 对,但你应该打电话 setValue 在迭代器返回的条目上,而不是调用 map.put . (这是 可能的 那个 地图放置 会有用的,但我不相信这是有保证的-然而医生说 entry.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);
        }
    }
    

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

    旧答案

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

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

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

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

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

    在这一点上你很好,因为你没有对场景做任何更改。

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

    机组支持元件拆除, 删除相应的 从地图映射,通过 迭代器.remove,set.remove, 清除、保留和清除 操作。它不支持 添加或添加所有操作。

    这甚至在 Map 接口本身。


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

        2
  •  12
  •   pstanton    15 年前

    您应该使用条目集:

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

    编辑固定代码