Alle Namen in einer Aufzählung als String abrufen []

95

Was ist der einfachste und / oder kürzeste Weg, um die Namen von Enum-Elementen als Array von Strings zu erhalten?

Damit meine ich, dass ich zum Beispiel die folgende Aufzählung hätte:

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;

    public static String[] names() {
        // ...
    }
}

Die names()Methode würde das Array zurückgeben { "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }.

Konstantin
quelle
2
Warum es keine native Enum-Methode gibt, die genau das tut, was mir
einfällt

Antworten:

91

Hier ist ein Einzeiler für jede enumKlasse:

public static String[] getNames(Class<? extends Enum<?>> e) {
    return Arrays.stream(e.getEnumConstants()).map(Enum::name).toArray(String[]::new);
}

Pre Java 8 ist immer noch ein Einzeiler, wenn auch weniger elegant:

public static String[] getNames(Class<? extends Enum<?>> e) {
    return Arrays.toString(e.getEnumConstants()).replaceAll("^.|.$", "").split(", ");
}

Das würdest du so nennen:

String[] names = getNames(State.class); // any other enum class will work

Wenn Sie nur etwas Einfaches für eine fest codierte Enum-Klasse möchten:

public static String[] names() {
    return Arrays.toString(State.values()).replaceAll("^.|.$", "").split(", ");
}
Böhmisch
quelle
2
Nicht die schnellsten Wege, um den Job zu erledigen, aber nette Regex.
ceklock
2
In Java 8 - Lösung, außerhalb eines Verfahrens Umfang, statt e.getEnumConstants()Sie verwenden könnenYourEnumName.values()
Eido95
1
@ Eido95 using YourEnumName.values()ruft eine statische Methode für die Klasse auf, die für keine Aufzählung wiederverwendet werden kann . Verwenden von getEnumConstants()Werken für jede Enum-Klasse. Die Idee mit dieser Methode ist, eine Dienstprogrammmethode neu zu erstellen, die Sie wie die letzte Zeile der Antwort aufrufen können.
Bohemian
Wenn Sie eine benutzerdefinierte Bezeichnung für Ihre Aufzählung wünschen, überschreiben Sie toString () in Ihrer Aufzählungsklasse.
Ralphgabb
Kannst du bitte erklären Class<? extends Enum<?>> e?
Carmageddon
63

Erstellen Sie ein String[]Array für die Namen und rufen Sie die statische values()Methode auf, die alle Aufzählungswerte zurückgibt. Durchlaufen Sie dann die Werte und füllen Sie das Namensarray.

public static String[] names() {
    State[] states = values();
    String[] names = new String[states.length];

    for (int i = 0; i < states.length; i++) {
        names[i] = states[i].name();
    }

    return names;
}
PermGenError
quelle
9
Warum values()13 Mal aufrufen und jedes Mal ein neues Array generieren, anstatt das Array in einer lokalen Variablen zwischenzuspeichern? Warum sollten Sie toString () verwenden, das überschreibbar ist, anstatt name()?
JB Nizet
@JBNizet heheh, ich tatsächlich versucht dies in meinem IDE und Weise zu faul ein Staat Array zu erstellen , ich denke, hehe, iedited es sowieso jetzt :)
PermGenError
2
Sie geben immer noch nicht die Namen zurück, sondern die toString () -Werte.
JB Nizet
@JBNizet hmm, tbh, ich weiß nicht wirklich, dass es name()bis jetzt eine Methode gab. wie dumm von mir: P danke, dass du mich informiert hast :)
PermGenError
1
Ich habe diese Antwort akzeptiert, aber eine Bearbeitung eingereicht, die den Code verbessert, damit er leichter zu lesen ist.
Konstantin
14

Hier ist eine elegante Lösung mit Apache Commons Lang 3 :

EnumUtils.getEnumList(State.class)

Obwohl eine Liste zurückgegeben wird, können Sie die Liste problemlos mit konvertieren list.toArray()

Sergio Trapiello
quelle
5
EnumUtils.getEnumList(enumClass)Gibt die Enum-Werte zurück, nicht die Strings. Sie könnten verwenden EnumUtils.getEnumMap(enumClass).keySet(), aber die Reihenfolge könnte anders sein.
Dan Halbert
11

Wenn Sie Java 8 verwenden können, funktioniert dies gut (Alternative zu Yuras Vorschlag, effizienter):

public static String[] names() {
    return Stream.of(State.values()).map(State::name).toArray(String[]::new);
}
Kris Boyd
quelle
9

Mit Java 8:

Arrays.stream(MyEnum.values()).map(Enum::name)
                    .collect(Collectors.toList()).toArray();
Yura Galavay
quelle
2
Während es wahrscheinlich funktioniert, ist diese Implementierung ziemlich ineffizient. Zuerst wird eine ArrayList erstellt, alle Elemente hinzugefügt, dann ein Array erstellt und alles erneut kopiert.
Daniel Bimschas
In Kürze werden "alle" Streams verwenden, um die grundlegendsten Operationen auszuführen ... und das ist keine sehr gute Idee.
marcolopes
Angesichts der Tatsache, dass die Anzahl der Elemente in Aufzählungen normalerweise eher gering ist, denke ich, dass die Lösung von Yura für viele Anwendungsfälle in Ordnung ist. Natürlich wird es von der spezifischen Situation abhängen ...
stefan.m
6

Ich würde es so schreiben

public static String[] names() {

    java.util.LinkedList<String> list = new LinkedList<String>();
    for (State s : State.values()) {
        list.add(s.name());
    }

    return list.toArray(new String[list.size()]);
}
Raymond Chenon
quelle
3

So etwas würde reichen:

public static String[] names() {
  String[] names = new String[values().length];
  int index = 0;

  for (State state : values()) {
    names[index++] = state.name();
  }

  return names;
}

Die Dokumentation empfiehlt die Verwendung toString()statt name()in den meisten Fällen , aber Sie haben für den Namen hier ausdrücklich gefragt.

Dave Webb
quelle
1
Obwohl dies nicht besonders wichtig ist, bietet eine reguläre for-Schleife in dieser Situation eine bessere Leistung als eine foreach-Schleife. Außerdem wird values()es zweimal aufgerufen, wenn es nur einmal aufgerufen werden muss.
FThompson
1
@Vulcan Ich denke, Leistung wäre nur dann ein Problem, wenn sie hunderttausend Mal ausgeführt würde. Außerdem values()ist eine Methode vom Compiler generiert, also denke ich, dass sie ziemlich optimiert ist. Schließlich erinnere ich mich, dass ich irgendwo gelesen habe, dass for-each-Schleifen effizienter als Standard sind, inkrementell für Schleifen, aber andererseits - es spielt einfach keine Rolle .
Konstantin
@Konstantin in Anbetracht dessen, dass die foreach-Schleife in Java mit einem Standard für die for-Schleife implementiert ist, wo immer Sie lesen, dass foreach-Schleifen immer effizienter sind, ist falsch.
sage88
1
@ sage88 Ich bezog mich auf Schleifen, in denen Sie Elemente mithilfe eines numerischen Index abrufen, den Sie in jedem Zyklus erhöhen. Zum Beispiel: for (int i = 0; i < a.length; i++) /* do stuff */;In diesem Fall foreach-Schleifen sind in der Tat effizienter. Eine schnelle SO-Suche zu diesem Thema gibt uns Folgendes
Konstantin
@Konstantin Jedes Mal, wenn Sie eine Datenstruktur haben, die einen wahlfreien Zugriff ermöglicht, wie dies bei Enum-Werten der Fall ist, die ein Array zurückgeben, ist eine for-Schleife im C-Stil schneller als die Verwendung einer for-Schleife für jede Schleife. Die für jede Schleife muss einen Iterator generieren, was sie langsamer macht. Der Link, den Sie gepostet haben, enthält ein Beispiel für die Verwendung einer Standard-for-Schleife in einer verknüpften Liste mit get (i), was natürlich schlimmer ist. Bei Verwendung einer Datenstruktur mit nicht wahlfreiem Zugriff ist die für jede Schleife schneller, bei Arrays ist der Overhead jedoch höher. Da es sich um ein primitives Array und nicht um eine ArrayList handelt, wird die Leistung von .size () nicht beeinträchtigt.
sage88
3

Andere Möglichkeiten:

Erster

Arrays.asList(FieldType.values())
            .stream()
            .map(f -> f.toString())
            .toArray(String[]::new);

Andere Weise

Stream.of(FieldType.values()).map(f -> f.toString()).toArray(String[]::new);
Durgpal Singh
quelle
1
In diesem Fall toString()funktioniert, im allgemeinen Fall jedoch nicht, da toString()überschrieben werden kann. Verwenden Sie, .name()um zuverlässig die Instanz zu erhalten Namen als String.
Böhmisch
2

Meine Lösung mit Manipulation von Strings (nicht die schnellste, aber kompakte):

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;

    public static String[] names() {
        String valuesStr = Arrays.toString(State.values());
        return valuesStr.substring(1, valuesStr.length()-1).replace(" ", "").split(",");
    }
}
ceklock
quelle
und Java7-konform!
Wassermann Power
1

Ich würde es so machen (aber ich würde wahrscheinlich Namen zu einer nicht veränderbaren Menge anstelle eines Arrays machen):

import java.util.Arrays;
enum State {
    NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
    public static final String[] names=new String[values().length];
    static {
        State[] values=values();
        for(int i=0;i<values.length;i++)
            names[i]=values[i].name();
    }
}
public class So13783295 {
    public static void main(String[] args) {
        System.out.println(Arrays.asList(State.names));
    }
}
Ray Tayek
quelle
Ich würde so etwas auch tun, wenn ich die Aufzählungsnamen wiederholt abrufen müsste, aber da die names()Methode nur sparsam aufgerufen wird, halte ich es für in Ordnung, ein Array vor Ort zu generieren.
Konstantin
1

Ich habe das gleiche Bedürfnis und verwende eine generische Methode (innerhalb einer ArrayUtils-Klasse):

public static <T> String[] toStringArray(T[] array) {
    String[] result=new String[array.length];
    for(int i=0; i<array.length; i++){
        result[i]=array[i].toString();
    }
    return result;
}

Und definieren Sie einfach eine STATIK in der Aufzählung ...

public static final String[] NAMES = ArrayUtils.toStringArray(values());

Java-Enums vermissen wirklich eine names () - und get (index) -Methode, sie sind wirklich hilfreich.

marcolopes
quelle
1

der gewöhnliche Weg (Wortspiel beabsichtigt):

String[] myStringArray=new String[EMyEnum.values().length];
for(EMyEnum e:EMyEnum.values())myStringArray[e.ordinal()]=e.toString();
Wassermann-Kraft
quelle
1

Ich habe ein bisschen an der Lösung von @ Bohemian getestet. Die Leistung ist besser, wenn stattdessen eine naive Schleife verwendet wird.

public static <T extends Enum<?>> String[] getEnumNames(Class<T> inEnumClass){
    T [] values = inEnumClass.getEnumConstants();
    int len = values.length;
    String[] names = new String[len];
    for(int i=0;i<values.length;i++){
        names[i] = values[i].name();
    }
    return names;
}

//Bohemian's solution
public static String[] getNames(Class<? extends Enum<?>> e) {
    return Arrays.stream(e.getEnumConstants()).map(Enum::name).toArray(String[]::new);
}
Futter
quelle
Sie sollten die Statistiken über die Leistung angeben, damit die Benutzer selbst beurteilen können, ob der Leistungsverlust erheblich ist oder nicht. Ich nehme an, dass die meisten Leute keine 100+ oder 1000+ Werte für eine Aufzählung haben werden.
Rauni Lillemets
1

org.apache.commons.lang3.EnumUtils.getEnumMap (State.class) .keySet ()

Wutzebaer
quelle
Was ist EnumUtils?
Stephan
@wutzebaer Downvoting, weil diese Lösung nicht vollständig ist - es gibt kein Array zurück
Zeile
0

Wenn Sie das kürzeste wollen, können Sie es versuchen

public static String[] names() {
    String test = Arrays.toString(values());
    return text.substring(1, text.length()-1).split(", ");
}
Peter Lawrey
quelle
Nicht die kürzeste :) Siehe meine Antwort für einen Einzeiler (der immer noch nur vales()einmal aufgerufen wird)
Bohemian
0

Nur ein Gedanke: Vielleicht müssen Sie keine Methode erstellen, um die Werte der Aufzählung als Array von Zeichenfolgen zurückzugeben.

Warum brauchen Sie eine Reihe von Zeichenfolgen? Möglicherweise müssen Sie die Werte nur konvertieren, wenn Sie sie verwenden, wenn Sie dies jemals tun müssen.

Beispiele:

for (State value:values()) {
    System.out.println(value); // Just print it.
}

for (State value:values()) {
    String x = value.toString(); // Just iterate and do something with x.
}

// If you just need to print the values:
System.out.println(Arrays.toString(State.values()));
ceklock
quelle
0

Eine andere Möglichkeit, dies in Java 7 oder früher zu tun, wäre die Verwendung von Guava:

public static String[] names() {
    return FluentIterable.from(values()).transform(Enum::name).toArray(String.class);
}
Justin Lee
quelle
0

Versuche dies:

public static String[] vratAtributy() {
    String[] atributy = new String[values().length];
    for(int index = 0; index < atributy.length; index++) {
        atributy[index] = values()[index].toString();
    }
    return atributy;
}
Matiseli
quelle
0

Sie können Enum-Werte in die Liste der Zeichenfolgen einfügen und in ein Array konvertieren:

    List<String> stateList = new ArrayList<>();

            for (State state: State.values()) {
                stateList.add(state.toString());
            }

    String[] stateArray = new String[stateList.size()];
    stateArray = stateList.toArray(stateArray);
Veljko P.
quelle
0

Der einfachste Weg:

Category[] category = Category.values();
for (int i = 0; i < cat.length; i++) {
     System.out.println(i  + " - " + category[i]);
}

Wobei Kategorie EnumName ist

Ilja Tarasovs
quelle