1. 概述

在这篇文章中,我们将讨论从Java HashMap 中移除条目的不同方法。

2. 引言

HashMap 使用唯一的键存储*(Key, Value)*对。一个想法是使用键作为标识符来从映射中移除关联的条目

我们可以利用java.util.Map接口提供的方法,通过键作为输入来进行条目移除。

2.1. 使用方法remove(Object key)

让我们通过一个简单的例子来尝试。我们有一个将食物项目与食物类型关联的映射:

HashMap<String, String> foodItemTypeMap = new HashMap<>();
foodItemTypeMap.put("Apple", "Fruit");
foodItemTypeMap.put("Grape", "Fruit");
foodItemTypeMap.put("Mango", "Fruit");
foodItemTypeMap.put("Carrot", "Vegetable");
foodItemTypeMap.put("Potato", "Vegetable");
foodItemTypeMap.put("Spinach", "Vegetable");

现在,我们从键为“Apple”的条目开始移除:

foodItemTypeMap.remove("Apple");
// Current Map Status: {Potato=Vegetable, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable}

2.2. 使用方法remove(Object key, Object value)

这是第一个方法的变体,接受键和值作为输入。在我们想要仅当键映射到特定值时删除条目的情况下,我们会使用这个方法。

foodItemTypeMap中,“Grape”键并未映射到“Vegetable”值。

因此,下面的操作不会导致任何更新:

foodItemTypeMap.remove("Grape", "Vegetable");
// Current Map Status: {Potato=Vegetable, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable}

现在,让我们探讨在HashMap中进行其他条目移除场景。

3. 在迭代过程中移除条目

HashMap类是非同步的。如果尝试并发地添加或删除条目,可能会导致ConcurrentModificationException。因此,我们需要在外部同步移除操作

3.1. 在外部对象上同步

一种方法是在封装HashMap的对象上同步。例如,我们可以使用java.util.Map接口的entrySet()方法获取HashMap中的条目集合。返回的集合由关联的Map支持。

因此,集合的任何结构修改都会导致Map的更新

让我们使用这种方法从foodItemTypeMap中移除条目:

Iterator<Entry<String, String>> iterator = foodItemTypeMap.entrySet().iterator();
while (iterator.hasNext()) {
    if (iterator.next().getKey().equals("Carrot"))
        iterator.remove();
}

除非我们在迭代器本身的方法中进行更新,否则可能不支持对映射的结构修改。如上代码片段所示,我们在迭代器对象上调用remove()方法,而不是在映射上。这提供了线程安全的移除操作。

在Java 8或更高版本中,我们可以使用removeIf操作来实现相同的结果

foodItemTypeMap.entrySet()
  .removeIf(entry -> entry.getKey().equals("Grape"));

3.2. 使用ConcurrentHashMap<K, V>

java.util.concurrent.ConcurrentHashMap类提供了线程安全的操作ConcurrentHashMap的迭代器一次只使用一个线程,因此它们为并发操作提供了确定性行为。

我们可以使用ConcurrencyLevel指定允许的并发线程操作数。

让我们在ConcurrentHashMap中使用基本的remove方法移除条目:

ConcurrentHashMap<String, String> foodItemTypeConcMap = new ConcurrentHashMap<>();
foodItemTypeConcMap.put("Apple", "Fruit");
foodItemTypeConcMap.put("Carrot", "Vegetable");
foodItemTypeConcMap.put("Potato", "Vegetable");

for (Entry<String, String> item : foodItemTypeConcMap.entrySet()) {
    if (item.getKey() != null && item.getKey().equals("Potato")) {
        foodItemTypeConcMap.remove(item.getKey());
    }
}

4. 总结

我们已经探讨了Java HashMap 中不同条目移除场景。如果不进行迭代,我们可以安全地使用java.util.Map接口提供的标准移除方法。

在迭代过程中更新Map时,必须在封装对象上使用remove方法。此外,我们还分析了一个替代类ConcurrentHashMap,它提供了对Map进行线程安全更新操作的能力。