[英]Hashmap.keySet(), foreach, and remove
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(). 我知道使用java的“foreach”从列表中删除通常是一个很大的禁忌,并且应该使用iterator.remove()。 But is it safe to remove() if I'm looping over a HashMap's keySet()?
但是如果我循环遍历HashMap的keySet(),那么remove()是否安全? Like this:
像这样:
for(String key : map.keySet()) {
Node n = map.get(key).optimize();
if(n == null) {
map.remove(key);
} else {
map.put(key, n);
}
}
EDIT: 编辑:
I hadn't noticed that you weren't really adding to the map - you were just changing the value within the entry. 我没有注意到你没有真正添加到地图 - 你只是改变了条目中的值。 In this case, pstanton's (pre-edit 1 ) solution is nearly right, but you should call
setValue
on the entry returned by the iterator, rather than calling map.put
. 在这种情况下,pstanton(编辑前1 )解决方案几乎是正确的,但是你应该在迭代器返回的条目上调用
setValue
,而不是调用map.put
。 (It's possible that map.put
will work, but I don't believe it's guaranteed - whereas the docs state that entry.setValue
will work.) (
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()
返回的HashSet.keySet()
是键的视图,而不是快照。
You can remove 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.
该集支持元素删除,它通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作从地图中删除相应的映射。 It does not support the add or addAll operations.
它不支持add或addAll操作。
This is even specified within the Map
interface itself. 这甚至在
Map
接口本身中指定。
1 I 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的答案,因为我认为我得到的类似但不同的情况的额外信息对于值得这个答案保持足够有用。
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 编辑固定代码
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.