java - Hashmap.keySet()、foreach 和删除

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

最佳答案

编辑:

我没有注意到您并没有真正添加到 map 中——您只是在更改条目中的值。在这种情况下,pstanton 的 (pre-edit1) 解决方案几乎是正确的,但是您应该在迭代器返回的条目上调用 setValue,而不是调用 map.put。 (可能 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 循环语法,使其不那么笨拙。)

旧答案

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

不——您既不应该添加到 map 也不应该直接从 map 中移除。 HashSet.keySet() 返回的集合是键的 View ,而不是快照。

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

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

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

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

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

The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.

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


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

关于java - Hashmap.keySet()、foreach 和删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2026104/

相关文章:

java - 如何在 geotools 中创建一个简单的 map 比例尺

java - 检查JRE是否安装在不同的操作系统上?

java - 如何调用包含 Graphics g 的函数

python - tensorflow - TFRecordWriter 在写入文件时占用太多内存?

java - 无法在sqlite数据库查询(JAVA)中使用输入作为参数

javascript - 当我每次函数调用创建一个新的生成器时,为什么这个生成器函数包装器会消耗迭代器?

python - 通过返回迭代器而不是列表来保存 Py3k 内存

c# - 如何循环遍历对象列表并在 C# 中搜索字符串

c# - ListView 中的 foreach 语句

sql - SQL中的foreach?