Java Hashmap.keySet()、foreach和remove
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2026104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hashmap.keySet(), foreach, and remove
提问by Sam Washburn
I know that it's typically a big no-no to remove from a list using java's "foreach" and that one should use iterator.remove(). But is it safe to remove() if I'm looping over a HashMap's keySet()? Like this:
我知道使用 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);
}
}
采纳答案by Jon Skeet
EDIT:
编辑:
I hadn't noticed that you weren't really addingto the map - you were just changing the value within the entry. In this case, pstanton's (pre-edit1) solution is nearlyright, but you should call setValue
on the entry returned by the iterator, rather than calling map.put
. (It's possiblethat map.put
will work, but I don't believe it's guaranteed - whereas the docs state that entry.setValue
willwork.)
我没有注意到您并没有真正添加到地图中 - 您只是更改了条目中的值。在这种情况下,pstanton 的(预编辑1)解决方案几乎是正确的,但您应该调用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);
}
}
(It's a shame that entry
doesn't have a remove
method, otherwise you could still use the enhanced for loop syntax, making it somewhat less clunky.)
(遗憾的是entry
没有remove
方法,否则您仍然可以使用增强的 for 循环语法,使其不那么笨拙。)
Old answer
旧答案
(I've left this here for the more general case where you just want to make arbitrary modifications.)
(我把这个留在这里是为了更一般的情况,你只想进行任意修改。)
No - you should neither add to the map nor remove from it directly. The set returned by HashSet.keySet()
is a view onto the keys, not a snapshot.
不 - 您既不应该添加到地图中,也不应该直接从中删除。返回的集合HashSet.keySet()
是键上的视图,而不是快照。
You canremove via the iterator, although that requires that you use the iterator explicitly instead of via an enhanced for loop.
您可以通过迭代器删除,尽管这要求您显式使用迭代器而不是通过增强的 for 循环。
One simple option is to create a new set from the original:
一个简单的选择是从原始集创建一个新集:
for (String key : new HashSet<String>(map.keySet())) {
...
}
At this point you're fine, because you're not making any changes to the set.
在这一点上,您很好,因为您没有对集合进行任何更改。
EDIT: Yes, you can definitely remove elements via the key set iterator. From the docs for HashMap.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.
该集合支持元素移除,通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作从映射中移除相应的映射。它不支持 add 或 addAll 操作。
This is even specified within the Map
interface itself.
这甚至在Map
接口本身中指定。
1I decided to edit my answer rather than just commenting on psanton's, as I figured the extra information I'd got for similar-but-distinct situations was sufficiently useful to merit this answer staying.
1我决定编辑我的答案,而不是仅仅评论 psanton 的答案,因为我认为我为类似但不同的情况获得的额外信息足够有用,值得保留这个答案。
回答by pstanton
you should use the entry set:
您应该使用条目集:
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);
}
EDIT fixed code
编辑固定代码