1. 概要

この記事では、Java HashMapからエントリを削除するさまざまな方法について説明します。

2. 序章

HashMap は、一意のキーを持つ(Key、Value)ペアのエントリを格納します。 したがって、1つのアイデアは、キーを識別子として使用して、関連するエントリをマップから削除することです。

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. 外部オブジェクトでの同期

1つのアプローチは、HashMapをカプセル化するオブジェクトで同期することです。 たとえば、 java.util.MapインターフェイスのentrySet()メソッドを使用して、HashMap[のエントリのSetをフェッチできます。 X146X]。 返されたSetは、関連付けられたMapによってサポートされています。

したがって、 Set の構造を変更すると、Mapも更新されます。 

このアプローチを使用して、foodItemTypeMapからエントリを削除しましょう。

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

更新にイテレータ独自のメソッドを使用しない限り、マップの構造変更はサポートされない可能性があります。 上記のスニペットでわかるように、マップの代わりにイテレータオブジェクトでremove()メソッドを呼び出しています。 これにより、スレッドセーフな削除操作が提供されます。

removeIf操作を使用して、Java8以降でも同じ結果を得ることができます。

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

3.2. 使用する ConcurrentHashMap

java.util.concurrent.ConcurrentHashMap クラスは、スレッドセーフな操作を提供します。 ConcurrentHashMap のイテレーターは、一度に1つのスレッドのみを使用します。 したがって、それらは同時操作の決定論的動作を可能にします。

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メソッドを使用する必要があります。 さらに、Mapでスレッドセーフな更新操作を可能にする代替クラスConcurrentHashMapを分析しました。