it-swarm.com.de

Konvertieren Sie den Ordinalwert in Enum

Ich habe den Enummentyp ReportTypeEnum, der in allen Klassen zwischen den Methoden übergeben wird. Ich muss ihn dann jedoch an die URL übergeben, sodass ich die ordinale Methode verwende, um den int-Wert zu erhalten. Nachdem ich es auf meiner anderen JSP-Seite erhalten habe, muss ich es in eine ReportTypeEnum-Datei konvertieren, damit ich es weitergeben kann. 

Wie kann ich Ordinal in ReportTypeEnum konvertieren?

Java 6 SE verwenden.

273
Lennie

Um eine Ordinalzahl in ihre Enumendarstellung zu konvertieren, möchten Sie möglicherweise Folgendes tun:

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

Bitte beachten Sie die Arraygrenzen. 

Beachten Sie, dass jeder Aufruf von values() ein neu geklontes Array zurückgibt, was die Leistung negativ beeinflussen kann. Sie können das Array zwischenspeichern, wenn es häufig aufgerufen wird. 

Codebeispiel zum Zwischenspeichern von values() .


Diese Antwort wurde bearbeitet, um das Feedback in die Kommentare aufzunehmen

555
Joachim Sauer

Das ist fast sicher eine schlechte Idee . Wenn die Ordnungszahl de-facto dauerhaft ist (z. B. weil jemand die URL mit einem Lesezeichen versehen hat), bedeutet dies sicherlich, dass Sie die Reihenfolge der enum immer beibehalten müssen.

Warum nicht die enum mit myEnumValue.name() kodieren (und über ReportTypeEnum.valueOf(s) dekodieren)?

135
oxbow_lakes

Wenn ich values() häufig benutze:

enum Suit {
   Hearts, Diamonds, Spades, Clubs;
   public static final Suit values[] = values();
}

Inzwischen wo.Java:

Suit suit = Suit.values[ordinal];

Achte auf deine Arraygrenzen.

83
QED

Sie könnten verwenden eine statische Nachschlagetabelle:

public enum Suit {
  spades, hearts, diamonds, clubs;

  private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();

  static{
    int ordinal = 0;
    for (Suit suit : EnumSet.allOf(Suit.class)) {
      lookup.put(ordinal, suit);
      ordinal+= 1;
    }
  }

  public Suit fromOrdinal(int ordinal) {
    return lookup.get(ordinal);
  }
}
7
Jan

Ich stimme den meisten Menschen zu, dass die Verwendung der Ordinalzahl wahrscheinlich eine schlechte Idee ist. Normalerweise löse ich dieses Problem, indem ich der Aufzählung einen privaten Konstruktor gebe, der beispielsweise einen DB-Wert annehmen und dann eine statische fromDbValue-Funktion erstellen kann, die der in Jans Antwort ähnlich ist.

public ReportTypeEnum {
    R1(1),
    R2(2),
    R3(3),
    R4(4),
    R5(5),
    R6(6),
    R7(7),
    R8(8);

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);  
    private static Map<Integer, ReportTypeEnum> lookup;
    private Integer dbValue;

    private ReportTypeEnum(Integer dbValue) {
        this.dbValue = dbValue;
    }


    static {
        try {
            ReportTypeEnum[] vals = ReportTypeEnum.values();
            lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);

            for (ReportTypeEnum  rpt: vals)
                lookup.put(rpt.getDbValue(), rpt);
         }
         catch (Exception e) {
             // Careful, if any exception is thrown out of a static block, the class
             // won't be initialized
             log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
         }
    }

    public static ReportTypeEnum fromDbValue(Integer dbValue) {
        return lookup.get(dbValue);
    }

    public Integer getDbValue() {
        return this.dbValue;
    }

}

Jetzt können Sie die Reihenfolge ändern, ohne die Suche zu ändern, und umgekehrt.

6
jmkelm08

Das ist was ich benutze. Ich behaupte nicht, dass es weit weniger "effizient" ist als die einfacheren Lösungen oben. Es wird eine viel klarere Ausnahmemeldung als "ArrayIndexOutOfBounds" bereitgestellt, wenn in der obigen Lösung ein ungültiger Ordinalwert verwendet wird.

Dabei wird die Tatsache ausgenutzt, dass EnumSet Javadoc die Iterator-Elemente in ihrer natürlichen Reihenfolge zurückgibt. Es gibt eine Behauptung, wenn das nicht richtig ist.

Der JUnit4-Test demonstriert seine Verwendung.

 /**
 * convert ordinal to Enum
 * @param clzz may not be null
 * @param ordinal
 * @return e with e.ordinal( ) == ordinal
 * @throws IllegalArgumentException if ordinal out of range
 */
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
    EnumSet<E> set = EnumSet.allOf(clzz);
    if (ordinal < set.size()) {
        Iterator<E> iter = set.iterator();
        for (int i = 0; i < ordinal; i++) {
            iter.next();
        }
        E rval = iter.next();
        assert(rval.ordinal() == ordinal);
        return rval;
    }
    throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}

@Test
public void lookupTest( ) {
    Java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
    System.out.println(tu);
}
4
gerardw
public enum Suit implements Java.io.Serializable, Comparable<Suit>{
  spades, hearts, diamonds, clubs;
  private static final Suit [] lookup  = Suit.values();
  public Suit fromOrdinal(int ordinal) {
    if(ordinal< 1 || ordinal> 3) return null;
    return lookup[value-1];
  }
}

die Testklasse

public class MainTest {
    public static void main(String[] args) {
        Suit d3 = Suit.diamonds;
        Suit d3Test = Suit.fromOrdinal(2);
        if(d3.equals(d3Test)){
            System.out.println("Susses");
        }else System.out.println("Fails");
    }
}

Ich weiß es zu schätzen, dass Sie uns mitteilen, wenn Sie einen effizienteren Code haben.

0
Ar maj

Das mache ich mit Proguard auf Android:

public enum SomeStatus {
    UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order

    private static SomeStatus[] values = null;
    public static SomeStatus fromInteger(int i) {
        if(SomeStatus.values == null) {
            SomeStatus.values = SomeStatus.values();
        }
        if (i < 0) return SomeStatus.values[0];
        if (i >= SomeStatus.values.length) return SomeStatus.values[0];
        return SomeStatus.values[i];
    }
}

es ist kurz und ich muss mir keine Sorgen um eine Ausnahme in Proguard machen

0

Eine Möglichkeit ist doExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];, die funktioniert und es ist einfach. Wie bereits erwähnt, gibt ExampleEnum.values() für jeden Aufruf ein neues geklontes Array zurück. Das kann unnötig teuer sein. Wir können das lösen, indem wir das Array wie folgt ExampleEnum[] values = values() zwischenspeichern. Es ist auch "gefährlich", die Änderung unseres zwischengespeicherten Arrays zuzulassen. Jemand könnte ExampleEnum.values[0] = ExampleEnum.type2; schreiben. Also würde ich es mit einer Accessor-Methode privat machen, die nicht extra kopiert.

private enum ExampleEnum{
    type0, type1, type2, type3;
    private static final ExampleEnum[] values = values();
    public static ExampleEnum value(int ord) {
        return values[ord];
    }
}

Sie würden ExampleEnum.value(ordinal) verwenden, um den mit ordinal verknüpften Aufzählungswert abzurufen.

0
joe pelletier

Sie können eine einfache Methode wie folgt definieren:

public enum Alphabet{
    A,B,C,D;

    public static Alphabet get(int index){
        return Alphabet.values()[index];
    }
}

Und benutze es wie folgt:

System.out.println(Alphabet.get(2));
0
Amir Forsati