几种删除HashMap中的Entry的方法

By | 2022年3月1日

概述

一个 HashMap 将Entry存储在具有唯一键的(键,值)对中。 如果您尝试再次添加相同的键,则该特定键的值将被覆盖。

我们可以使用键从 HashMap 中删除条目,因为键在 HashMap 中是唯一的。

通过remove(Object key) 方法删除

官方说明文档:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/HashMap.html#remove(java.lang.Object)

假设我们有如下的数据

HashMap<String, String> foodItemTypeMap = new HashMap<>();

foodItemTypeMap.put("Apple", "Fruit");
foodItemTypeMap.put("Banana", "Fruit");
foodItemTypeMap.put("Pineapple", "Fruit");
foodItemTypeMap.put("Grape", "Fruit");
foodItemTypeMap.put("Mango", "Fruit");
foodItemTypeMap.put("Carrot", "Vegetable");
foodItemTypeMap.put("Potato", "Vegetable");
foodItemTypeMap.put("Spinach", "Vegetable");

现在需求来了,我们要删除【Pineapple】的数据

public class RemoveEntryHashMap {

  public static void main(String[] args) {
    HashMap<String, String> foodItemTypeMap = new HashMap<>();
    foodItemTypeMap.put("Apple", "Fruit");
    foodItemTypeMap.put("Banana", "Fruit");
    foodItemTypeMap.put("Pineapple", "Fruit");
    foodItemTypeMap.put("Grape", "Fruit");
    foodItemTypeMap.put("Mango", "Fruit");
    foodItemTypeMap.put("Carrot", "Vegetable");
    foodItemTypeMap.put("Potato", "Vegetable");
    foodItemTypeMap.put("Spinach", "Vegetable");
    System.out.println("HashMap before any entry removal");
    System.out.println(foodItemTypeMap);
    foodItemTypeMap.remove("Pineapple");
    System.out.println("HashMap after entry removal");
    System.out.println(foodItemTypeMap);
  }
}

输出:

HashMap before any entry removal
{Potato=Vegetable, Apple=Fruit, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Pineapple=Fruit, Spinach=Vegetable, Banana=Fruit}
HashMap after entry removal
{Potato=Vegetable, Apple=Fruit, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable, Banana=Fruit}

通过remove(Object key, Object value)方法删除

官方说明:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Map.html#remove(java.lang.Object,java.lang.Object)

这个 remove(Object key, Object value) 与上面使用的 remove(Object key) 方法非常相似,但主要区别在于它接受 key 和 value 作为参数。

仅当键和值都与 remove 方法中指定的键值匹配时,它才会从 HashMap 中删除条目。

例如,下面提到的代码片段不会在 HashMap 中执行任何更新,因为数据库中不存在具有相似键值的条目。

foodItemTypeMap.remove("Pineapple", "Vegetable");
System.out.println("HashMap after entry removal");
System.out.println(foodItemTypeMap);

输出:

HashMap after entry removal
{Potato=Vegetable, Apple=Fruit, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Pineapple=Fruit, Spinach=Vegetable, Banana=Fruit}

下面的代码删除了键 Banana 和值 Fruits 的条目,正如我们在 remove 方法中指定的 (Pineapple, Fruit) 作为参数,并且在 HashMap 中存在一个具有相似键值对的条目。

foodItemTypeMap.remove("Pineapple", "Fruit");
System.out.println("HashMap after entry removal");
System.out.println(foodItemTypeMap);

输出:

HashMap after entry removal
{Potato=Vegetable, Apple=Fruit, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable, Banana=Fruit}

循环中删除

如果您详细了解 HashMap,那么您必须知道 HashMap 是不同步的。 这意味着如果我们尝试同时添加或删除entry可能会遇到 ConcurrentModificationException。

由于这个原因,需要在外部同步删除操作。

解决这个问题的方法是我们可以使用 java.util.Map 接口的 entrySet() 方法。 它将为我们提供 HashMap 中存在的条目集。

由于返回的entry由关联的 Map 支持,因此如果我们对条entry执行任何结构更改,那么也会对 HashMap 进行更新。

请注意,除非我们使用迭代器自己的方法进行更新,否则可能不支持对Map的结构修改。

下面是此示例代码片段。

public class RemoveEntryHashMap {

  public static void main(String[] args) {
    HashMap<String, String> foodItemTypeMap = new HashMap<>();
    foodItemTypeMap.put("Apple", "Fruit");
    foodItemTypeMap.put("Banana", "Fruit");
    foodItemTypeMap.put("Pineapple", "Fruit");
    foodItemTypeMap.put("Grape", "Fruit");
    foodItemTypeMap.put("Mango", "Fruit");
    foodItemTypeMap.put("Carrot", "Vegetable");
    foodItemTypeMap.put("Potato", "Vegetable");
    foodItemTypeMap.put("Spinach", "Vegetable");
    System.out.println("HashMap before any entry removal");
    System.out.println(foodItemTypeMap);
    Iterator<Entry<String, String>> iterator = foodItemTypeMap.entrySet().iterator();
    while (iterator.hasNext()) {
      if (iterator.next().getKey().equals("Pineapple")) {
        iterator.remove();
      }
    }
    System.out.println("HashMap after entry removal");
    System.out.println(foodItemTypeMap);
  }
}

输出:

HashMap before any entry removal
{Potato=Vegetable, Apple=Fruit, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Pineapple=Fruit, Spinach=Vegetable, Banana=Fruit}
HashMap after entry removal
{Potato=Vegetable, Apple=Fruit, Carrot=Vegetable, Grape=Fruit, Mango=Fruit, Spinach=Vegetable, Banana=Fruit}

如果是Java8以上,那么下面是更简便的写法

System.out.println("HashMap before any entry removal");
System.out.println(foodItemTypeMap);
foodItemTypeMap.entrySet()
.removeIf(entry -> entry.getKey().equals("Pineapple"));
System.out.println("HashMap after entry removal");
System.out.println(foodItemTypeMap);

也可以通过ConcurrentHashMap解决同步的问题

public class RemoveEntryHashMap {

  public static void main(String[] args) {
    ConcurrentHashMap<String, String> foodItemTypeMap = new ConcurrentHashMap<>();
    foodItemTypeMap.put("Apple", "Fruit");
    foodItemTypeMap.put("Banana", "Fruit");
    foodItemTypeMap.put("Pineapple", "Fruit");
    foodItemTypeMap.put("Grape", "Fruit");
    foodItemTypeMap.put("Mango", "Fruit");
    foodItemTypeMap.put("Carrot", "Vegetable");
    foodItemTypeMap.put("Potato", "Vegetable");
    foodItemTypeMap.put("Spinach", "Vegetable");
    System.out.println("HashMap before any entry removal");
    System.out.println(foodItemTypeMap);
    for (Entry<String, String> item : foodItemTypeMap.entrySet()) {
      if (item.getKey() != null && item.getKey().equals("Potato")) {
        foodItemTypeMap.remove(item.getKey());
      }
    }
    System.out.println("HashMap after entry removal");
    System.out.println(foodItemTypeMap);
  }
}