2013-06-09 5 views
39

Angenommen, ich habe eine Enumeration:Was ist der beste Weg, `next` und` previous` für einen Enum-Typ zu implementieren?

enum E { 
    A, B, C; 
} 

Wie in this answer von lucasmo werden in einem statischen Array in der Reihenfolge gespeicherten Werte Enum gezeigt, dass sie initialisiert werden, und Sie können später abgerufen werden (ein Klon) dieses Array mit E.values().

Jetzt nehme ich an E#getNext und E#getPrevious so implementieren möchten, dass alle folgenden Ausdrücke auswerten zu true:

E.A.getNext() == E.B 
E.B.getNext() == E.C 
E.C.getNext() == E.A 

E.A.getPrevious() == E.C 
E.B.getPrevious() == E.A 
E.C.getPrevious() == E.B 

Meine aktuelle Implementierung für getNext ist folgende:

public E getNext() { 
    E[] e = E.values(); 
    int i = 0; 
    for (; e[i] != this; i++) 
     ; 
    i++; 
    i %= e.length; 
    return e[i]; 
} 

und eine ähnliche Methode für getPrevious.

Allerdings scheint dieser Code umständlich besten (zB „leer“ for Schleife, arguable Missbrauch einer Zählvariable und möglicherweise fehlerhaft im schlimmsten Fall (Denken Reflexion, möglicherweise).

Was wäre der beste Weg, zu implementieren getNext und getPrevious Methoden für enum-Typen in Java 7


HINWEIS: Meine Anfrage ich nicht die Absicht, diese Frage subjektiv zu sein für den „best“ Implemen. Es ist eine Kurzform, nach der Implementierung zu fragen, die am schnellsten, saubersten und am besten wartbar ist.

+0

'E.C.getPrevious() == E.C' oder' E.C.getPrevious() == E.B'? – johnchen902

+0

@ johnchen902 behoben; Entschuldigung – wchargin

Antwort

58

Versuchen Sie folgendes:

public static enum A { 
    X, Y, Z; 
    private static A[] vals = values(); 
    public A next() 
    { 
     return vals[(this.ordinal()+1) % vals.length]; 
    } 

Implementierung von previous() wird als Übung, aber daran erinnern, dass in Java, the modulo a % b can return a negative number.

EDIT: Wie vorgeschlagen, eine private statische Kopie der values() Array zu vermeiden Array-Kopieren jedes Mal next() oder previous() wird aufgerufen.

+1

Ah! Ich kannte "Ordinal" nicht; Ich suchte nach "indexOf". Wäre es besser, 'A [] values ​​= values ​​()' zu deklarieren, um ein zweimaliges Klonen zu vermeiden? – wchargin

+0

Ich würde mich wundern, wenn ein Klonen beteiligt wäre, da Enum-Werte Singletons sind. Sie können sich den generierten Code immer ansehen. –

+1

Die 'values' Methode gibt' (A []) ($ VALUES.clone()) 'where' private static final A [] $ VALUES = neu A [] {X, Y, Z} 'zurück. Siehe [diese Antwort] (http://stackoverflow.com/a/1163121/732016). – wchargin

4

Alternativ kann man irgendwie entlang der Linien der folgenden Idee gehen:

public enum SomeEnum { 
    A, B, C; 

    public Optional<SomeEnum> next() { 
    switch (this) { 
     case A: return Optional.of(B); 
     case B: return Optional.of(C); 
     // any other case can NOT be mapped! 
     default: return Optional.empty(); 
    } 
} 

Hinweise:

  1. Im Gegensatz zu den anderen Antwort, auf diese Weise hat einige implizite Mapping; anstatt sich auf ordinal() zu verlassen. Natürlich bedeutet das mehr Code; aber es zwingt auch den Autor zu betrachten was es bedeutet, neue Konstanten hinzuzufügen oder vorhandene zu entfernen. Wenn Sie sich auf ordinal verlassen, ist Ihre implizite Annahme, dass die Bestellung auf der Reihenfolge basiert, die für die Enum-Konstante-Deklaration verwendet wird. Wenn also jemand 6 Monate später wiederkommt und eine neue Konstante hinzufügen muss, muss er verstehen, dass die neue Konstante Y X, Y, Z ... braucht, anstatt nur X, Z, Y anzufügen!
  2. Es kann Situationen geben, in denen es keinen Sinn macht, dass die "letzte" Enum-Konstante den "ersten" als Nachfolger hat. Denken Sie an T-Shirt Größen für Beispiele. XXL.next() ist sicher nicht XS. In solchen Fällen ist die Verwendung von Optional die geeignetere Antwort.
+0

Hallo, GhostCat. Ich nehme an, dass ich dies nicht explizit in der Frage angegeben hatte, aber ich hoffte auf eine automatisch erweiterbare Lösung (d. H. Nicht "rohe Gewalt"), unter der Annahme, dass die Standardreihenfolge logisch ist. Ich denke nicht wirklich, dass dies die Frage beantwortet, aber Ihr Argument, dass die Standardreihenfolge möglicherweise nicht wünschenswert ist, ist in der Tat wertvoll. – wchargin

+1

Gern geschehen; Ich bin gerade auf eine andere Frage gestoßen und dachte: Besonders der optionale Teil wäre eine eigene Antwort wert. – GhostCat

+0

Ja. Ich liebe was "Optional" sein könnte und habe es in größeren Projekten richtig gemacht; es ist schade, dass es sich nicht gut in den Rest der Sprache integriert. – wchargin

Verwandte Themen