Home > Informatik > Begriffe und Konzepte > Enumerations

Enumerations

Definition

Enumerations

Eine Enumeration (kurz enum) ist in Java ein spezieller Datentyp, mit dem man eine feste, endliche Menge von Konstanten definieren kann.

Ein E. wird verwendet, wenn eine Variable nur bestimmte, klar abgegrenzte Werte annehmen darf – zum Beispiel die Wochentage, Himmelsrichtungen oder Gegenstandsarten in einem Spiel.

Beispiel 1a
public enum Wochentag
{
    MONTAG, DIENSTAG, MITTWOCH, DONNERSTAG, FREITAG, SAMSTAG, SONNTAG
}
Beispiel 1b
public enum Anspruchsniveau
{
    LEICHT, MITTELSCHWER, SCHWER, EXTREM
}
Beispiel 1c
public enum Instrument
{
    GITARRE, BASS, SCHLAGZEUG, KEYBOARD, GESANG
}

Enumerations können als eigene Klasse in einer eigenen Java-Datei erstellt werden (Wochentag.java, Anspruchsniveau.java bzw. Instrument.java), oder sie können als innere Klasse in einer anderen (äußeren) Klasse stehen, wie das Beispiel 2 zeigt.

Beispiel 2
public class Altersauswertung
{
    public enum Altersgruppe
    {
       BABY, JUGENDLICHER, KIND, KLEINKIND, ERWACHSENER, RENTNER, ERROR
    }
    
    private Altersgruppe bestimmeAltersgruppe(int alter)
    {
       if (alter <  0) return Altersgruppe.ERROR; else
       if (alter <  2) return Altersgruppe.BABY; else
       if (alter <  6) return Altersgruppe.KLEINKIND; else
       if (alter < 14) return Altersgruppe.KIND; else
       if (alter < 18) return Altersgruppe.JUGENDLICHER; else
       if (alter < 67) return Altersgruppe.ERWACHSENER; else
       return Altersgruppe.RENTNER;
    }
    
    public void kleinerTest(int alter)
    {
       Altersgruppe gruppe = bestimmeAltersgruppe(alter);
       System.out.println("Mit " + alter + " Jahren: " + gruppe);
    }
}

Der Quelltext in Beispiel 2 definiert eine Klasse Altersauswertung, mit der ein Alter wie 12, 20 oder 60 einer bestimmten Altersgruppe zugeordnet werden kann.

Die Enumeration Altersgruppe steht innerhalb der Klasse Altersauswertung. Sie ist damit eine innere Enumeration, also eine Enumeration, die innerhalb einer anderen Klasse definiert wurde. Diese Aufzählung legt fest, welche Altersgruppen im Programm überhaupt erlaubt sind.

Die Enumeration übernimmt in diesem Beispiel die Rolle eines eigenen Datentyps. Eine Variable vom Typ Altersgruppe kann nur einen dieser festgelegten Werte annehmen. Dadurch ist der Rückgabewert der Methode bestimmeAltersgruppe() klar begrenzt und weniger fehleranfällig als ein einfacher String.

In der Methode bestimmeAltersgruppe(int alter) wird das übergebene Alter geprüft. Je nach Zahlenbereich liefert die Methode einen passenden Enumerationswert zurück, zum Beispiel:

return Altersgruppe.BABY;

Für negative Altersangaben wird hier keine Ausnahme geworfen, sondern Altersgruppe.ERROR zurückgegeben. Das ist eine einfache Möglichkeit, ungültige Eingaben zu kennzeichnen.

Die Methode kleinerTest(int alter) verwendet die Enumeration indirekt. Zuerst ruft sie die Methode bestimmeAltersgruppe(alter) auf und speichert den Rückgabewert in einer Variablen vom Typ Altersgruppe:

Altersgruppe gruppe = bestimmeAltersgruppe(alter);

Anschließend wird dieser Wert ausgegeben:

System.out.println("Mit " + alter + " Jahren: " + gruppe);

Dabei erscheint der Name des Enumerationswertes automatisch als Text, zum Beispiel:

Mit 15 Jahren: JUGENDLICHER

Das Beispiel zeigt, dass eine Enumeration verwendet werden kann, wenn es eine feste, überschaubare Menge von möglichen Ergebnissen gibt. Die Methode liefert dann keinen beliebigen Text und keine schwer verständliche Zahl zurück, sondern einen klar benannten Wert des Datentyps Altersgruppe.

Vorteile von Aufzählungstypen (Enumerations)

  • Eine Variable kann nur einen in der Enumeration definierten Wert annehmen, keinen anderen.
  • Enumerationen helfen, Tippfehler zu vermeiden, wie sie bei der Verwendung von Strings leicht auftreten können.
  • Ein Enum-Wert ist meistens verständlicher als eine Zahl. Altersgruppe.JUGENDLICHER ist verständlicher als 4.
  • Der Compiler überprüft, ob nur Werte der Enumeration verwendet werden.
  • Entwicklungsumgebungen wie IntelliJ zeigen die möglichen Werte einer E. automatisch an und unterstützen so die automatische Vervollständigung von Code.
  • Werden später weitere Werte benötigt, müssen diese nur in der Definition der E. ergänzt werden.

Merke:

Enumerations

Enumerations eignen sich immer dann, wenn eine Variable nur eine feste und überschaubare Menge von möglichen Werten annehmen soll. Typische Beispiele sind Wochentage, Jahreszeiten, Ampelzustände, Schwierigkeitsgrade, Instrumente oder Altersgruppen.

Enumerationen mit "inneren Werten"

Bei einer Enumeration können die einzelnen Enumerationswerte zusätzliche Informationen speichern. Dazu benötigt die Enumeration Instanzvariablen und einen Konstruktor.

Beispiel 1

Hier ein einfaches Beispiel aus der Astronomie:

public enum Planet
{
	 MERKUR(88),
	 VENUS(225),
	 ERDE(365),
	 MARS(687);

	 private int umlaufzeit;

	 private Planet(int umlaufzeit)
	 {
		  this.umlaufzeit = umlaufzeit;
	 }

	 public int getUmlaufzeit()
	 {
		  return umlaufzeit;
	 }
}

Die eigentliche Enumeration besteht in der Aufzählung der vier Planeten MERKUR, VENUS, ERDE und MARS. In Klammern sind hier zusätzlich die Umlaufzeiten der Planeten in Tagen angegeben:

ERDE(365)

Damit dies funktioniert, benötigt die Enumeration eine eigene Instanzvariable für diese Umlaufzeit sowie einen Konstruktor, dem man diese Zahl übergeben kann. Mit der Methode getUmlaufzeit() kann man sich die jeweilige Umlaufzeit zurückgeben lassen – ähnlich wie bei einer "richtigen" Java-Klasse mit ihren Getter-Methoden.

Wie funktioniert nun das Ganze?

Die Anweisung ERDE(365) in der Enumeration erzeugt intern ein Objekt der Klasse Planet und übergibt dabei den Wert 365 an den Konstruktor. Der Konstruktor speichert diesen Wert anschließend in der Instanzvariablen umlaufzeit des jeweiligen Objekts.

Betrachten wir nun ein Beispiel, in dem diese erweiterte Enumeration verwendet wird:

public class TestPlanet
{
	 public static void main(String[] args)
	 {
		  Planet p = Planet.ERDE;

		  System.out.println(p.getUmlaufzeit());
	 }
}

Mit

Planet p = Planet.ERDE;

wird eine Referenz auf das bereits vorhandene Enumerationsobjekt Planet.ERDE in der Variablen p gespeichert. Die Umlaufzeit von 365 Tagen muss hier nicht mit angegeben werden, da sie bereits beim Anlegen des Enumerationswertes festgelegt wurde.

Bei dieser erweiterten Enumeration ist also jede Konstante ein eigenes Objekt mit einer Instanzvariable und einer Getter-Methode.

Mit p.getUmlaufzeit() kann auf diese Instanzvariable zugegriffen werden. In der Konsole wird dann die Zahl 365 ausgegeben.

Beispiel 2

Der Aufzählungstyp Planet hatte eine Instanzvariable und nur eine Getter-Methode. Betrachten wir nun einen etwas komplexeren Aufzählungstyp mit zwei Instanzvariablen und drei Getter-Methoden:

public enum Schwierigkeitsgrad
{
    LEICHT(1, "für Anfänger geeignet"),
    MITTEL(2, "für Fortgeschrittene geeignet"),
    SCHWER(3, "anspruchsvolle Aufgabe"),
    EXPERTE(4, "sehr schwierige Aufgabe");

    private int stufe;
    private String beschreibung;

    private Schwierigkeitsgrad(int stufe, String beschreibung)
    {
        this.stufe = stufe;
        this.beschreibung = beschreibung;
    }

    public int getStufe()
    {
        return stufe;
    }

    public String getBeschreibung()
    {
        return beschreibung;
    }

    public boolean istSchwer()
    {
        return stufe >= 3;
    }
}

Der Konstruktor ist nötig, um jeden Schwierigkeitsgrad (LEICHT, MITTEL, ...) mit einer Zahl und einem String zu verknüpfen; beide Angaben werden dabei in den beiden Instanzvariablen gespeichert. Die beiden ersten Getter-Methoden liefern die Werte dieser Instanzvariablen zurück, die dritte Getter-Methode istSchwer() liefert true zurück, falls der Schwierikgeitsgrad mindestens 3 beträgt (SCHWER).

Schauen wir uns nun ein kleines Testprogramm an:

public class TestSchwierigkeitsgrad
{
    public static void main(String[] args)
    {
        Schwierigkeitsgrad grad = Schwierigkeitsgrad.SCHWER;

        System.out.println(grad.getStufe());
        System.out.println(grad.getBeschreibung());

        if (grad.istSchwer())
            System.out.println("Diese Aufgabe ist schwierig.");
    }
}

Hier wird eine Referenz auf das bereits vorhandene Enumerationsobjekt Schwierigkeitsgrad.SCHWER in der Variablen grad gespeichert. Anschließend werden die Methoden getStufe(), getBeschreibung() und istSchwer() aufgerufen, um die Eigenschaften dieses Enumerationsobjekts auszuwerten.

Quellen:

  1. Lahres, Bernhard; Rayman, Frank; Strube, Gerhard: Objektorientierte Programmierung. 3. Auflage. Bonn: Rheinwerk Computing, 2021.
  2. Barnes, David J.; Kölling, Michael: Java lernen mit BlueJ – Objects First. 6. Auflage. Hallbergmoos: Pearson Studium, 2019.
  3. Ullenboom, Christian: Java ist auch eine Insel. 17. Auflage. Bonn: Rheinwerk Computing, 2023.