Ich möchte die These "Enums in Java5 schlecht umgesetzt?"
mal zum Ärger ablassen in den Raum stellen.
Zur Vorgeschichte:
Ich bastel gerade für meine Kollegen an einer Einführung in
Java5, da wir unseren nächsten Projektmeilenstein damit umsetzen
wollen. Dadurch habe ich jetzt das erste mal wirklich Zeit mich mit
Java5 zu beschäftigen. Das letzte Jahr über habe ich für
meine Diplomarbeit ja die eine oder andere Kleinigkeit in C# gemacht,
ich kenne also beide Welten.
Als ich mich gestern mit Java5 Enums befasst habe, da bin ich über
einige Unstimmigkeiten gestolpert, die ich am besten am Beispiel der
Lösung in C# versuche zu beschreiben.
In beiden Sprachen ist es möglich automatisch nummerierte Enums zu
erzeugen:
public enum Words {
FOO, BAR, FROTZ
}
so weit, so gut.
C# Enums leiten sich von Zahlen ab, d.h. ein Element einer Enum
ist
selber eine Zahl (von der Runtime aus gesehen), im Gegensatz zu Java5,
wo ein Element nur eine Zahl
hat (die Ordnungszahl, zugreifbar mit
ordinal(), beginnt bei 0, wird
immer automatisch vergeben).
Hierdurch ist es in C# möglich, die folgende Enum zu deklarieren:
public enum Words {
FOO=1,
BAR=2,
FROTZ=3
}
Ich kann also einer Enum (wie einer Konstanten) einen Wert geben. Dies
ermöglicht es mir Enums (und somit Typsicherheit) auch an Stellen
einzusetzen, wo es auf den konkreten Wert eines Elements ankommt (Thema
'Außenanbindung'). Beispiele hierfür sind z.B. Interaktionen mit
anderen Sprachen über Webservices, wo ich den Wert für die
Schnittstelle festschreiben muß, oder der Fall, wo ich eine Enum
in eine relationale Datenbank speichern möchte. Hier waere es
blöd, wenn nach einer Programmänderung, also dem hinzufügen
einer Enum, sich plötzlich die Werte verändern, weil das neue
Element nicht am Ende eingefügt worden ist (was durchaus mal
passieren kann). Und ja, ich denke das ist ein
echtes Problem in
einem Umfeld mit ~30 Entwicklern an einem Projekt und einigen millionen
Zeilen in ~100 Tabellen.
Möchte ich das gleiche in Java tun, so muß ich die Enum
folgendermaßen definieren:
public enum Words {
FOO(1),
BAR(2),
FROTZ(3);
public int val;
private Word(int v) {
val = v;
}
}
Nun habe ich wieder eine Zahl, mit der ich nach 'außen' arbeiten kann.
Ich habe nur keinen Mechanismus eine Zahl in eine Enum zu überfuehren.
Den kann ich mir natürlich mit einer HashMap und einem passen Konstruktor
in der Enum selber basteln, aber das
will ich nicht müssen :-)
Es sei denn, ich übersehe jetzt etwas. Klar, ich kann in Java5 nach
außen immer mit dem Namen arbeiten, was aber im Falle von Datenbanken
schon wieder blöd ist (INT ist einfach besser zu handhaben als VARCHAR(20)).
Das folgende Stück C# Code:
public enum Direction {
NORTH=1,SOUTH=2,EAST=3,WEST=4
}
public Direction invert(Direction dir);
läßt sich z.B. als Webservice mit
public int invert(int dir) {
return invert((Direction) dir);
}
realisieren (Konvertierungen
Enum->int sind implizit,
int->Enum
explizit).
In Java5
muß ich mit Strings arbeiten, wenn ich den Automatismus will:
public enum Direction {
NORTH,SOUTH,EAST,WEST
}
public Direction invert(Direction dir);
public String invert(String dir) {
return invert(Direction.valueOf(dir)).name();
}
Fazit:
Ich finde, Sun hat es gründlich versaut. Für mich sieht das nach einer
"Oh, guck mal, Microsoft hat das bei C# so gemacht, dann machen wir das halt komplett
anders, damit keiner sagt wir hätten abgeguckt" - Entscheidung aus.