Motivation
Das Problem
Wie kann ich …
- … einen festen Satz von Werten vorgeben?
- … dafür sorgen, dass nur diese Werte und kein anderer Wert übergeben werden kann?
- … die Werte typsicher machen?
- … mir dabei die Überprüfung vom Compiler abnehmen lassen?
- … die Werte in gängigen Kontrollstrukturen verwenden?
In der fortgeschrittenen Programmierung benötigt man sehr häufig Methoden, bei denen über einen Parameter eine Auswahl getroffen werden kann, die sich aus einer begrenzten Menge von Möglichkeiten bestimmt. Beispiele sind die Auswahl einer Textauszeichnung (fett, kursiv, unterstrichen) in einer Textverarbeitung oder ein Wochentag in einem Kalender. In beiden Fällen kann man zwar einen int
verwenden und einfach festlegen, welche Zahl welche Bedeutung haben soll, dies ist aber nicht elegant und vor allem fehleranfällig.
Eigentlich möchte man eine Möglichkeit, die benötigten Konstanten für die Übergabe zu definieren und der Compiler soll sicherstellen, dass beim Aufruf nur eine dieser Konstanten verwendet werden kann (typsicher).
Schön wäre es zusätzlich noch, wenn man diese Konstanten in allen Kontrollstrukturen (if
und case
) verwenden könnte.
Beispiel: Das Problem
public class Wochentag {
public static final int MONTAG = 1;
public static final int DIENSTAG = 2;
public static final int MITTWOCH = 3;
public static final int DONNERSTAG = 4;
public static final int FREITAG = 5;
public static final int SAMSTAG = 6;
public static final int SONNTAG = 7;
}
public class DateJuggler {
public void setWochentag(int wochentag) { ... }
public int getWochentag() { ... }
}
DateJuggler dj = new DateJuggler();
dj.setWochentag(Wochentag.FREITAG);
dj.setWochentag(Wochentag.FREITAG + 100);
int wochentag = dj.getWochentag();
Das Beispiel zeigt das Problem, wenn man keine Unterstützung für für die oben erwähnten Konstanten in der Programmiersprache hat. Es gibt eine ganze Reihe von Fehlerquellen:
- Bei der Definition der Konstanten (
MONTAG
,DIENSTAG
, …) muss man aufpassen, dass man keinen der Werte doppelt verwendet. Würde manSONNTAG
aus Versehen ebenfalls auf6
setzen, käme es zu subtilen, schwer zu findenden Fehlern. - Man kann nicht sicherstellen, dass der Verwender nur eine der vorhandenen Konstanten verwendet. Da die Methode
setWochentag
einenint
nimmt, kann man jede Zahl übergeben, auch unsinnige Tage wie10
oderFREITAG + 100
. 3. Innerhalb der MethodesetWochentag
muss man also durch eine Überprüfung noch einmal feststellen, ob der übergebende Wert im gewünschten Bereich liegt. Wenn nicht, muss man entweder eine Ausnahme werfen oder aber einen Standardwert annehmen.
Die Lösung: Enumerationen (Enums)
Enumeration (enumeration)
- Konstrukt, um festen Satz von Konstanten zu definieren
- Typsicher und vom Compiler überprüft
- Funktionieren mit
if
undswitch
- Syntax:
[Sichtbarkeit] enum { CONST1, CONST2, ... ; }
public enum Planet {
MERKUR, VENUS, ERDE, MARS,
JUPITER,SATURN, URANUS, NEPTUN;
// PLUTO;
}
Java bietet mit den sogenannten Enumerationen eine Lösung für das beschriebene Problem. Mit ihnen kann man einen festen Satz von Konstanten definieren, wobei der Compiler überprüft, dass ein Verwender nur die erlaubten Konstanten übergeben kann.
In dem hier gegebenen Beispiel sehen wir eine Enumeration (Enum) mit dem Namen Planet
, die acht Enum-Konstanten (nämlich die Planeten) enthält.
Technisch gesehen ist eine Enumeration einer Klasse sehr ähnlich. Sie führt einen neuen Typ ein (hier Planet
) und erzeugt automatisch Objekte für die vorhandenen Konstanten (hier MERKUR
, VENUS
, ERDE
, …). Sie wird hinter den Kulissen tatsächlich als Klasse realisiert, wobei es aber einige Besonderheiten gibt, die später noch erläutert werden. Zu jeder Enumeration gibt es also:
- Eine Klasse für die Enumeration
- Genau ein Objekt pro Konstante, die in der Enumeration deklariert wurde
Da eine Enumeration einen neuen Typ einführt, kann man von ihrem Typ Referenzvariablen deklarieren und damit auf die Konstanten-Objekte zeigen: Planet p = Planet.MERKUR
Beispiel: Mit Enumerationen
public enum Wochentag {
MONTAG, DIENSTAG, MITTWOCH, DONNERSTAG, FREITAG, SAMSTAG, SONNTAG;
}
public class DateJuggler {
public void setWochentag(Wochentag wochentag) { ... }
public Wochentag getWochentag() { ... }
}
DateJuggler dj = new DateJuggler();
dj.setWochentag(Wochentag.FREITAG);
dj.setWochentag(Wochentag.FREITAG + 100); // FEHLER!!
Wochentag wochentag = dj.getWochentag();
Dieses Beispiel zeigt noch einmal die Klasse DateJuggler
, jetzt aber mithilfe von Enumerationen realisiert. Die Konstanten befinden sich jetzt in der neu geschaffenen Enumeration Wochentag
. Die setWochentag
-Methode bekommt keinen int
mehr übergeben, sondern eine der Konstanten aus Wochentag
, was durch den Typ des Parameters angezeigt wird.
Der Verwender von setWochentag
kann jetzt die Methode nur noch mit einer der vorhandenen Konstanten aufrufen, jeder Versuch etwas anderes zu übergeben führt zu einem Fehler.