Eine Anleitung zu EnumMap

1. Übersicht

EnumMap ist eine Map- Implementierung, die ausschließlich Enum als Schlüssel verwendet.

In diesem Tutorial werden die Eigenschaften, allgemeinen Anwendungsfälle und der Zeitpunkt der Verwendung erläutert.

2. Projekteinrichtung

Stellen Sie sich eine einfache Anforderung vor, bei der wir Wochentage mit dem Sport abbilden müssen, den wir an diesem Tag spielen:

Monday Soccer Tuesday Basketball Wednesday Hiking Thursday Karate 

Hierfür könnten wir eine Aufzählung verwenden:

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

Was wir bald sehen werden, wird der Schlüssel für unsere Karte sein.

3. Schöpfung

Um EnumMap zu erkunden , müssen wir zunächst eine instanziieren:

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

Und hier ist unser erster Unterschied zu etwas Üblicherem wie HashMap . Beachten Sie, dass mit HashMap die Typparametrisierung ausreichend ist, was bedeutet, dass wir mit neuem HashMap () davonkommen können . Allerdings EnumMap erfordert den Schlüsseltyp im Konstruktor .

3.1. EnumMap Copykonstruktor

EnumMap wird auch mit zwei Kopierkonstruktoren geliefert . Die erste nimmt eine andere EnumMap :

EnumMap activityMap = new EnumMap(DayOfWeek.class); activityMap.put(DayOfWeek.MONDAY, "Soccer"); activityMap.put(DayOfWeek.TUESDAY, "Basketball"); EnumMap 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 Copy Constructor

Oder wenn wir eine nicht leere Karte haben, deren Schlüssel eine Aufzählung ist, können wir das auch tun:

Map 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");

Beachten Sie, dass die Karte nicht leer sein darf, damit EnumMap den Schlüsseltyp aus einem vorhandenen Eintrag ermitteln kann.

Wenn die angegebene Zuordnung mehr als einen Aufzählungstyp enthält, löst der Konstruktor ClassCastException aus .

4. Hinzufügen und Abrufen von Elementen

Nachdem wir eine EnumMap instanziiert haben , können wir unseren Sport mit der put () -Methode hinzufügen :

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

Und um es abzurufen, können wir get () verwenden :

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

5. Auf Elemente prüfen

Um zu überprüfen, ob für einen bestimmten Tag eine Zuordnung definiert ist, verwenden wir includesKey () :

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

Und um zu überprüfen, ob eine bestimmte Sportart einem von uns verwendeten Schlüssel zugeordnet ist, enthältValue () :

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

5.1. null als Wert

Jetzt ist null ein semantisch gültiger Wert für EnumMap .

Lassen Sie uns null mit „nichts tun“ verknüpfen und es dem Samstag zuordnen:

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. Elemente entfernen

Um die Zuordnung eines bestimmten Tages aufzuheben, entfernen wir ihn einfach () :

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

Wie wir sehen können, gibt remove (key) den vorherigen Wert zurück, der dem Schlüssel zugeordnet ist, oder null, wenn für den Schlüssel keine Zuordnung vorhanden war.

Wir können auch festlegen , dass die Zuordnung eines bestimmten Tages nur dann aufgehoben wird, wenn dieser Tag einer bestimmten Aktivität zugeordnet ist:

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

remove (Schlüssel, Wert) entfernt den Eintrag für den angegebenen Schlüssel nur, wenn der Schlüssel derzeit dem angegebenen Wert zugeordnet ist.

7. Sammlungsansichten

Genau wie bei normalen Karten können wir bei jeder EnumMap drei verschiedene Ansichten oder Untersammlungen haben.

First, let's create a new map of our activities:

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

7.1. values

The first view of our activity map is values() which, as the name suggests, returns all the values in the map:

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

Note here that EnumMap is an ordered map. It uses the order of the DayOfWeek enum to determine the order of the entries.

7.2. keySet

Similarly, keySet() returns a collection of the keys, again in enum order:

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

7.3. entrySet

Lastly, entrySet() returns the mapping in pairs of key and value:

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

Ordering in a map can certainly come in handy, and we go into more depth in our tutorial that compares TreeMap to HashMap.

7.4. Mutability

Now, remember that any changes we make in the original activity map will be reflected in any of its views:

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

And vice-versa; any changes we make the sub-views will be reflected in the original activity map:

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

Per EnumMap‘s contract with Map interface, the sub-views are backed by the original map.

8. When to Use EnumMap

8.1. Performance

Using Enum as key makes it possible to do some extra performance optimization, like a quicker hash computation since all possible keys are known in advance.

The simplicity of having enum as key means EnumMap only need to be backed up by a plain old Java Array with very simple logic for storage and retrieval. On the other hand, generic Map implementations need to cater for concerns related to having a generic object as its key. For example, HashMap needs a complex data structure and a considerably more complex storing and retrieval logic to cater for the possibility of hash collision.

8.2. Functionality

Also, as we saw, EnumMap is an ordered map, in that its views will iterate in enum order. To get similar behavior for more complex scenarios, we can look at TreeMap or LinkedHashMap.

9. Conclusion

In diesem Artikel haben wir die EnumMap- Implementierung der Map- Oberfläche untersucht. Wenn Sie mit Enum als Schlüssel arbeiten, kann EnumMap nützlich sein.

Der vollständige Quellcode für alle in diesem Tutorial verwendeten Beispiele befindet sich im GitHub-Projekt.