以有效的方式从 Map 中删除多个键?

我有一个具有大量键值对的 Map<String,String>。现在我要从 Map中删除选定的键。下面的代码展示了我为实现这一点所做的工作。

Set keySet = new HashSet(); //I added keys to keySet which I want to remove.

然后:

Iterator entriesIterator = keySet.iterator();
while (entriesIterator.hasNext()) {
map.remove( entriesIterator.next().toString());
}

这样很好,有什么更好的方法吗?

112056 次浏览

假设您的集合包含要删除的字符串,则可以使用 keySetmap.keySet().removeAll(keySet);

keySet返回此映射中包含的键的 Set 视图。集合由映射支持,因此映射的更改反映在集合中,反之亦然。

人为的例子:

Map<String, String> map = new HashMap<>();
map.put("a", "");
map.put("b", "");
map.put("c", "");


Set<String> set = new HashSet<> ();
set.add("a");
set.add("b");


map.keySet().removeAll(set);


System.out.println(map); //only contains "c"

只是为了完整起见:

正如猜测的那样,java.util.AbstractSet#removeAll实际上遍历了所有条目,但有一个小技巧: 它使用较小集合的迭代器:

if (size() <= collection.size()) {
Iterator<?> it = iterator();
while (it.hasNext()) {
if (collection.contains(it.next())) {
it.remove();
}
}
} else {
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
remove(it.next());
}
}

使用 Java 流:

keySet.forEach(map::remove);

为了完成任务,并且当你在寻找实现这一目标的方法时,谷歌会把你带到这里:

map.entrySet().removeIf(entry -> /* decide what you want to remove here */ );

这并不假设您有一组预定义的键要删除,而是假设您有一个条件,在这个条件下键应该被删除。根据这个问题,目前还不清楚这些键是手动添加的还是基于某种条件添加的。在后一种情况下,这可能是更干净的代码。

对于前一种情况,这种(未测试的)代码也可以工作:

map.entrySet().removeIf(entry -> keySet.contains(entry.getKey()) );

但显然 @ assylias 提供的答案在这种情况下要干净得多!