1. 概要

EnumMap は、[X23X]Enumをキーとして排他的に使用するMap実装です。

このチュートリアルでは、そのプロパティ、一般的な使用例、およびいつ使用する必要があるかについて説明します。

2. プロジェクトの設定

曜日をその日にプレイするスポーツとマッピングする必要がある単純な要件を想像してみてください。

Monday     Soccer                         
Tuesday    Basketball                     
Wednesday  Hiking                         
Thursday   Karate

このために、列挙型を使用できます。

public enum DayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

すぐに表示されるものが、マップのキーになります。

3. 創造

EnumMap の探索を開始するには、最初に1つをインスタンス化する必要があります。

EnumMap<DayOfWeek, String> activityMap = new EnumMap<>(DayOfWeek.class);
activityMap.put(DayOfWeek.MONDAY, "Soccer");

そして、これがHashMapのようなもっと一般的なものとの最初の違いです。 で注意してください HashMap 、型のパラメータ化で十分です。つまり、 新しいHashMap<>()。 ただし、EnumMapにはコンストラクターのキータイプが必要です

3.1. EnumMapコピーコンストラクタ

EnumMap には、2つのコピーコンストラクターも付属しています。 最初は別のEnumMapを取ります:

EnumMap<DayOfWeek, String> activityMap = new EnumMap<>(DayOfWeek.class);
activityMap.put(DayOfWeek.MONDAY, "Soccer");
activityMap.put(DayOfWeek.TUESDAY, "Basketball");

EnumMap<DayOfWeek, String> activityMapCopy = new EnumMap<>(dayMap);
assertThat(activityMapCopy.size()).isEqualTo(2);
assertThat(activityMapCopy.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");
assertThat(activityMapCopy.get(DayOfWeek.TUESDAY)).isEqualTo("Basketball");

3.2. マップコピーコンストラクタ

または、キーが列挙型である空でないマップがある場合は、それも実行できます:

Map<DayOfWeek, String> ordinaryMap = new HashMap();
ordinaryMap.put(DayOfWeek.MONDAY, "Soccer");

EnumMap enumMap = new EnumMap(ordinaryMap);
assertThat(enumMap.size()).isEqualTo(1);
assertThat(enumMap.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");

EnumMap が既存のエントリからキータイプを判別できるように、マップは空でない必要があることに注意してください。

指定されたマップに複数の列挙型が含まれている場合、コンストラクターはClassCastExceptionをスローします。

4. 要素の追加と取得

EnumMap をインスタンス化した後、 put()メソッドを使用してスポーツを追加できます。

activityMap.put(DayOfWeek.MONDAY, "Soccer");

そして、それを取得するには、 get()を使用できます。

assertThat(clubMap.get(DayOfWeek.MONDAY)).isEqualTo("Soccer");

5. 要素の確認

特定の日にマッピングが定義されているかどうかを確認するには、 containsKey()を使用します。

activityMap.put(DayOfWeek.WEDNESDAY, "Hiking");
assertThat(activityMap.containsKey(DayOfWeek.WEDNESDAY)).isTrue();

また、特定のスポーツが任意のキーにマップされているかどうかを確認するには、 containsValue()を使用します。

assertThat(activityMap.containsValue("Hiking")).isTrue();

5.1. nullを値として

現在、nullEnumMapの意味的に有効な値です。

null を「何もしない」と関連付けて、土曜日にマップしましょう。

assertThat(activityMap.containsKey(DayOfWeek.SATURDAY)).isFalse();
assertThat(activityMap.containsValue(null)).isFalse();
activityMap.put(DayOfWeek.SATURDAY, null);
assertThat(activityMap.containsKey(DayOfWeek.SATURDAY)).isTrue();
assertThat(activityMap.containsValue(null)).isTrue();

6. 要素の削除

特定の日のマップを解除するには、単に remove()それを実行します。

activityMap.put(DayOfWeek.MONDAY, "Soccer");
assertThat(activityMap.remove(DayOfWeek.MONDAY)).isEqualTo("Soccer");
assertThat(activityMap.containsKey(DayOfWeek.MONDAY)).isFalse();

ご覧のとおり、 remove(key)は、キーに関連付けられた以前の値を返します。キーのマッピングがなかった場合は、nullを返します。

特定の日が特定のアクティビティにマップされている場合にのみ、その日をマップ解除することもできます:

activityMap.put(DayOfWeek.Monday, "Soccer");
assertThat(activityMap.remove(DayOfWeek.Monday, "Hiking")).isEqualTo(false);
assertThat(activityMap.remove(DayOfWeek.Monday, "Soccer")).isEqualTo(true);

remove(key、value)は、キーが現在指定された値にマップされている場合にのみ、指定されたキーのエントリを削除します。

7. コレクションビュー

通常のマップと同様に、 EnumMap でも、3つの異なるビューまたはサブコレクションを持つことができます。

まず、私たちの活動の新しいマップを作成しましょう。

EnumMap<DayOfWeek, String> activityMap = new EnumMap(DayOfWeek.class);
activityMap.put(DayOfWeek.THURSDAY, "Karate");
activityMap.put(DayOfWeek.WEDNESDAY, "Hiking");
activityMap.put(DayOfWeek.MONDAY, "Soccer");

7.1. 

アクティビティマップの最初のビューはvalues()で、名前が示すように、マップ内のすべての値を返します。

Collection values = dayMap.values();
assertThat(values)
  .containsExactly("Soccer", "Hiking", "Karate");

ここで、EnumMapは順序付けられたマップであることに注意してください。 DayOfWeek 列挙型の順序を使用して、エントリの順序を決定します。

7.2.  keySet

同様に、 keySet()は、キーのコレクションを列挙型の順序で返します。

Set keys = dayMap.keySet();
assertThat(keys)
        .containsExactly(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.SATURDAY);

7.3.  entrySet

最後に、 entrySet()は、キーと値のペアでマッピングを返します。

assertThat(dayMap.entrySet())
    .containsExactly(
        new SimpleEntry(DayOfWeek.MONDAY, "Soccer"),
        new SimpleEntry(DayOfWeek.WEDNESDAY, "Hiking"),
        new SimpleEntry(DayOfWeek.THURSDAY, "Karate")
    );

マップでの順序付けは確かに便利です。チュートリアルでは、TreeMapとHashMapを比較する方法について詳しく説明します。

7.4. 可変性

ここで、元のアクティビティマップに加えた変更は、そのビューのいずれかに反映されることに注意してください。

activityMap.put(DayOfWeek.TUESDAY, "Basketball");
assertThat(values)
    .containsExactly("Soccer", "Basketball", "Hiking", "Karate");

およびその逆; サブビューに加えた変更は、元のアクティビティマップに反映されます。

values.remove("Hiking");
assertThat(activityMap.containsKey(DayOfWeek.WEDNESDAY)).isFalse();
assertThat(activityMap.size()).isEqualTo(3);

EnumMapMapインターフェースとの契約により、サブビューは元のマップに基づいています。

8. EnumMapを使用する場合

8.1. パフォーマンス

Enum をキーとして使用すると、可能なすべてのキーが事前にわかっているため、より高速なハッシュ計算のように、パフォーマンスをさらに最適化できます。

enum をキーとして使用するという単純さは、 EnumMap を、保存と取得のための非常に単純なロジックを備えた単純な古いJava Arrayでバックアップするだけでよいことを意味します。 一方、汎用マップの実装は、汎用オブジェクトをキーとして持つことに関連する懸念に対応する必要があります。 たとえば、 HashMap は、ハッシュの衝突の可能性に対応するために、複雑なデータ構造とかなり複雑な格納および取得ロジックを必要とします。

8.2. 機能性

また、これまで見てきたように、 EnumMap は順序付けられたマップであり、そのビューは列挙型の順序で繰り返されます。 より複雑なシナリオで同様の動作を取得するには、TreeMapまたはLinkedHashMapを確認します。

9. 結論

この記事では、MapインターフェースのEnumMap実装について説明しました。 Enum をキーとして使用する場合、EnumMapが便利です。

このチュートリアルで使用されているすべての例の完全なソースコードは、GitHubプロジェクトにあります。