1. Overview
1.概述
In this article, we’ll discuss different ways to remove an entry from a Java HashMap.
在这篇文章中,我们将讨论从JavaHashMap中删除一个条目的不同方法。
2. Introduction
2.绪论
HashMap stores entries in (Key, Value) pairs with unique keys. Thus, one idea would be to use the key as an identifier to remove an associated entry from the map.
HashMap以(Key, Value)对存储条目,其键值是唯一的。因此,一个想法是,使用键作为标识符,从地图中删除相关条目。
We can use the methods provided by the java.util.Map interface for entry removal using the key as an input.
我们可以使用java.util.Map接口提供的方法,使用键作为输入进行条目移除。
2.1. Using Method remove(Object key)
2.1.使用方法remove(Object key)
Let’s try it out using a simple example. We’ve got a map that associates food items with food types:
让我们用一个简单的例子来试试。我们有一张地图,将食品项目与食品类型联系起来。
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");
Let’s remove the entry with the key “Apple”:
让我们删除键为 “苹果 “的条目。
foodItemTypeMap.remove("Apple");
// Current Map Status: {Potato=Vegetable, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable}
2.2. Using Method remove(Object key, Object value)
2.2.使用方法remove(Object key, Object value)
This is a variant of the first method and accepts both key and value as inputs. We use this method in case we want to delete an entry only if a key is mapped to a specific value.
这是第一个方法的一个变种,接受key和value作为输入。我们使用这个方法的情况是,我们想只有当一个键被映射到一个特定的值时才删除一个条目。
In foodItemTypeMap, the key “Grape” is not mapped with the “Vegetable” value.
在foodItemTypeMap中,键 “Grape “没有与 “Vegetable “值映射。
As a result, the below operation won’t lead to any updates:
因此,下面的操作不会导致任何更新。
foodItemTypeMap.remove("Grape", "Vegetable");
// Current Map Status: {Potato=Vegetable, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable}
Now, let’s explore other scenarios of entry removal in a HashMap.
现在,让我们来探讨一下HashMap中删除条目的其他情况。
3. Removing an Entry While Iterating
3.迭代时删除一个条目
The HashMap class is unsynchronized. If we try to add or delete an entry concurrently, it might result in ConcurrentModificationException. Therefore, we need to synchronize the remove operation externally.
HashMap类是不同步的。如果我们试图同时添加或删除一个条目,可能会导致ConcurrentModificationException。因此,我们需要在外部同步remove操作。
3.1. Synchronizing on External Object
3.1.在外部对象上进行同步
One approach is to synchronize on an object that encapsulates the HashMap. For example, we can use the entrySet() method of the java.util.Map interface to fetch a Set of entries in a HashMap. The returned Set is backed by the associated Map.
一种方法是在一个封装了HashMap的对象上进行同步。例如,我们可以使用java.util.Map接口的entrySet()方法来获取HashMap中的Set条目。返回的Set是由相关的Map.支持的。
Thus, any structural modification of the Set would result in an update to the Map as well.
因此,对Set的任何结构性修改也会导致对Map的更新。
Let’s remove an entry from the foodItemTypeMap using this approach:
让我们用这种方法从foodItemTypeMap中删除一个条目。
Iterator<Entry<String, String>> iterator = foodItemTypeMap.entrySet().iterator();
while (iterator.hasNext()) {
if (iterator.next().getKey().equals("Carrot"))
iterator.remove();
}
Structural modifications on the map might not be supported unless we’re using the iterator’s own methods for an update. As we can see in the above snippet, we’re invoking the remove() method on the iterator object instead of the map. This provides a thread-safe removal operation.
除非我们使用迭代器自身的方法进行更新,否则可能不支持地图上的结构修改。正如我们在上面的片段中所看到的,我们在迭代器对象上调用了remove()方法,而不是地图。这提供了一个线程安全的移除操作。
We can achieve the same result in Java 8 or later using the removeIf operation:
我们可以在Java 8或更高版本中使用removeIf操作实现同样的结果。
foodItemTypeMap.entrySet()
.removeIf(entry -> entry.getKey().equals("Grape"));
3.2. Using ConcurrentHashMap<K, V>
3.2.使用ConcurrentHashMap<K, V>
The java.util.concurrent.ConcurrentHashMap class provides thread-safe operations. Iterators for ConcurrentHashMap use only one thread at a time. Hence, they enable deterministic behavior for concurrent operations.
java.util.concurrent.ConcurrentHashMap类提供了线程安全的操作。ConcurrentHashMap的迭代器一次只使用一个线程。因此,它们能够为并发操作提供确定性的行为。
We can specify the number of concurrent thread operations permitted using ConcurrencyLevel.
我们可以使用ConcurrencyLevel.指定允许的并发线程操作的数量。
Let’s use the basic remove method for removing entries in a ConcurrentHashMap:
让我们使用基本的remove方法来删除ConcurrentHashMap中的条目。
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. Conclusion
4.总结
We have explored different scenarios of entry removal in a Java HashMap. If not iterating, we can use the standard entry removal methods provided by the java.util.Map interface safely.
我们已经探索了Java HashMap中条目移除的不同情况。如果不进行迭代,我们可以安全地使用java.util.Map接口所提供的标准条目移除方法。
In case we’re updating the Map during iteration, it’s imperative to use remove methods on an encapsulating object. Additionally, we analyzed an alternative class, ConcurrentHashMap, that enables thread-safe update operations on Map.
如果我们在迭代过程中更新Map,就必须在一个封装对象上使用remove方法。此外,我们分析了一个替代类,ConcurrentHashMap,它能够对Map进行线程安全的更新操作。