Guide zu EnumSet

Anleitung zu EnumSet

1. Einführung

In diesem Tutorial werden wir dieEnumSet-Sammlung aus demjava.util-Paket untersuchen und ihre Besonderheiten diskutieren.

Wir werden zuerst die Hauptmerkmale der Sammlung zeigen und danach die Interna der Klasse durchgehen, um ihre Vorteile zu verstehen.

Abschließend werden die wichtigsten Vorgänge behandelt und einige grundlegende Beispiele implementiert.

2. Was ist einEnumSet

An EnumSet is a specialized Set collection to work with enum classes. Es implementiert dieSet-Schnittstelle und erstreckt sich vonAbstractSet:

image

ObwohlAbstractSet undAbstractCollection Implementierungen für fast alle Methoden der SchnittstellenSet undCollection bereitstellen, überschreibtEnumSet die meisten von ihnen.

Wenn wir einEnumSet verwenden möchten, müssen wir einige wichtige Punkte berücksichtigen:

  • It can contain only enum values und alle Werte müssen zu denselbenenum gehören

  • It doesn’t allow to add null values, wobei einNullPointerException geworfen wird, um dies zu versuchen

  • It’s not thread-safe, daher müssen wir es bei Bedarf extern synchronisieren

  • Die Elemente werden in der Reihenfolge gespeichert, in der sie inenum deklariert sind

  • It uses a fail-safe iterator, das für eine Kopie funktioniert, sodass keinConcurrentModificationException ausgegeben wird, wenn die Sammlung beim Durchlaufen geändert wird

3. WarumEnumSet verwenden?

Als Faustregel giltEnumSet should always be preferred over any other Set implementation when we are storing enum values.

In den nächsten Abschnitten werden wir sehen, was diese Sammlung besser macht als andere. Zu diesem Zweck zeigen wir kurz die Interna der Klasse, um ein besseres Verständnis zu erhalten.

3.1. Implementierungsdetails

EnumSet ist einepublicabstract-Klasse, die mehrere statische Factory-Methoden enthält, mit denen wir Instanzen erstellen können. Das JDK bietet zwei verschiedene Implementierungen:package-private und unterstützt durch einen Bitvektor:

  • RegularEnumSet und

  • JumboEnumSet

RegularEnumSet uses a single long to represent the bit vector. Jedes Bit deslong-Elements repräsentiert einen Wert vonenum. Der i-te Wert der Aufzählung wird im i-ten Bit gespeichert, sodass Sie leicht erkennen können, ob ein Wert vorhanden ist oder nicht. Since long is a 64-bit data type, this implementation can store up to 64 elements.

Auf der anderen SeiteJumboEnumSet uses an array of long elements as a bit vector.This lets this implementation store more than 64 elements. Es funktioniert ziemlich ähnlich wieRegularEnumSet, führt jedoch einige zusätzliche Berechnungen durch, um den Array-Index zu finden, in dem der Wert gespeichert ist.

Es ist nicht überraschend, dass das erste lange Element des Arrays die 64 ersten Werte vonenum, das zweite Element die nächsten 64 usw. speichert.

Die Factory-Methoden vonEnumSeterstellen Instanzen der einen oder anderen Implementierung, abhängig von der Anzahl der Elemente derenum:

if (universe.length <= 64)
    return new RegularEnumSet<>(elementType, universe);
else
    return new JumboEnumSet<>(elementType, universe);

Beachten Sie, dass nur die Größe der Klasseenumberücksichtigt wird, nicht die Anzahl der Elemente, die in der Sammlung gespeichert werden.

3.2. Vorteile der Verwendung vonEnumSet

Aufgrund der Implementierung vonEnumSet, die wir oben beschrieben haben,all the methods in an EnumSet are implemented using arithmetic bitwise operations. Diese Berechnungen sind sehr schnell und daher werden alle grundlegenden Operationen in einer konstanten Zeit ausgeführt.

Wenn wirEnumSet mit anderenSet-Implementierungen wieHashSet vergleichen, ist die erste normalerweise schneller, da die Werte in einer vorhersagbaren Reihenfolge gespeichert werden und nur ein Bit für jede Berechnung untersucht werden muss. Im Gegensatz zuHashSet müssen diehashcode nicht berechnet werden, um den richtigen Bucket zu finden.

Darüber hinaus ist einEnumSet aufgrund der Natur von Bitvektoren sehr kompakt und effizient. Aus diesem Grund wird weniger Arbeitsspeicher benötigt, mit allen Vorteilen, die sich daraus ergeben.

4. Hauptoperationen

Die meisten Methoden vonEnumSetfunktionieren wie alle anderenSet, mit Ausnahme der Methoden zum Erstellen von Instanzen.

In den nächsten Abschnitten werden alle Erstellungsmethoden detailliert dargestellt und der Rest der Methoden kurz behandelt.

In unseren Beispielen arbeiten wir mitColorenum:

public enum Color {
    RED, YELLOW, GREEN, BLUE, BLACK, WHITE
}

4.1. Erstellungsmethoden

The most simple methods to create an EnumSet are allOf() and noneOf(). Auf diese Weise können wir leicht einEnumSet erstellen, das alle Elemente unsererColor-Aufzählung enthält:

EnumSet.allOf(Color.class);

Ebenso können wirnoneOf() verwenden, um das Gegenteil zu tun und eine leere Sammlung vonColor zu erstellen:

EnumSet.noneOf(Color.class);

If we want to create an EnumSet with a subset of the enum elements we can use the overloaded of() methods. Es ist wichtig, zwischen den Methoden mit einer festen Anzahl von Parametern bis zu 5 verschiedenen und denen zu unterscheiden, dievarargs verwenden:

image

Der Javadoc gibt an, dass die Leistung dervarargs-Version aufgrund der Erstellung des Arrays langsamer sein kann als die der anderen. Daher sollten wir es nur verwenden, wenn wir anfangs mehr als 5 Elemente hinzufügen müssen.

Eine andere Möglichkeit, eine Teilmenge vonenum zu erstellen, ist die Verwendung der Methoderange():

EnumSet.range(Color.YELLOW, Color.BLUE);

Im obigen Beispiel enthältEnumSet alle Elemente vonYellow bisBlue.. Sie folgen der inenum definierten Reihenfolge:

[YELLOW, GREEN, BLUE]

Beachten Sie, dass es sowohl das erste als auch das letzte angegebene Element enthält.

Another useful factory method is the complementOf() that allows us to exclude the elements passed as parameters. Erstellen wir einEnumSet mit allenColor Elementen außer Schwarzweiß:

EnumSet.complementOf(EnumSet.of(Color.BLACK, Color.WHITE));

Wenn wir diese Sammlung drucken, können wir sehen, dass sie alle anderen Elemente enthält:

[RED, YELLOW, GREEN, BLUE]

Schließlichwe can create an EnumSet by copying all the elements from another EnumSet:

EnumSet.copyOf(EnumSet.of(Color.BLACK, Color.WHITE));

Intern wird die Methodecloneaufgerufen.

Darüber hinaus sindwe can also copy all the elements from any Collection that contains enum elements. Verwenden Sie es, um alle Elemente einer Liste zu kopieren:

List colorsList = new ArrayList<>();
colorsList.add(Color.RED);
EnumSet listCopy = EnumSet.copyOf(colorsList);

In diesem Fall enthältlistCopy nur die rote Farbe.

4.2. Sonstige Operationen

Der Rest der Operationen funktioniert genauso wie jede andere Implementierung vonSet, und es gibt keinen Unterschied in der Verwendung.

Daher können wir leicht ein leeresEnumSet erstellen und einige Elemente hinzufügen:

EnumSet set = EnumSet.noneOf(Color.class);
set.add(Color.RED);
set.add(Color.YELLOW)

Überprüfen Sie, ob die Sammlung ein bestimmtes Element enthält:

set.contains(Color.RED);

Iteriere über die Elemente:

set.forEach(System.out::println);

Oder einfach Elemente entfernen:

set.remove(Color.RED);

Dies gilt natürlich auch für alle anderen Operationen, die einSetunterstützt.

5. Fazit

In diesem Artikel haben wir die Hauptfunktionen vonEnumSet, seine interne Implementierung und wie wir davon profitieren können, gezeigt.

Wir haben auch die wichtigsten Methoden behandelt und einige Beispiele implementiert, um zu zeigen, wie wir sie verwenden können.

Wie immer ist der vollständige Quellcode der Beispieleover on GitHub verfügbar.