Obtention de tous les noms dans une énumération sous forme de chaîne []

96

Quel est le moyen le plus simple et / ou le plus court possible d'obtenir les noms des éléments enum sous forme de tableau de Strings?

Ce que je veux dire par là, c'est que si, par exemple, j'avais l'énumération suivante:

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

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

la names()méthode renverrait le tableau { "NEW", "RUNNABLE", "BLOCKED", "WAITING", "TIMED_WAITING", "TERMINATED" }.

Konstantin
la source
2
Pourquoi il n'y a pas de méthode native Enum qui fait exactement ça me dépasse ... et aussi un get (index) pour simplifier le get of value ()
marcolopes

Réponses:

91

Voici une ligne pour toutes les enumclasses:

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

Pre Java 8 est toujours un one-liner, bien que moins élégant:

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

Que vous appelleriez comme ceci:

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

Si vous voulez juste quelque chose de simple pour une classe enum codée en dur:

public static String[] names() {
    return Arrays.toString(State.values()).replaceAll("^.|.$", "").split(", ");
}
Bohème
la source
2
Pas les moyens les plus rapides de faire le travail, mais une belle regex.
ceklock
2
Dans la solution Java 8, en dehors de la portée de la méthode, au lieu de e.getEnumConstants()vous pouvez utiliserYourEnumName.values()
Eido95
1
@ Eido95 en utilisant YourEnumName.values()appelle une méthode statique sur la classe, qui ne peut être réutilisée pour aucune énumération. Utilisation de getEnumConstants()travaux pour n'importe quelle classe enum. L'idée avec cette méthode est de recréer une méthode utilitaire que vous pouvez appeler comme la dernière ligne de la réponse.
Bohème
si vous voulez une étiquette personnalisée pour votre énumération, remplacez toString () dans votre classe enum.
ralphgabb
Pouvez-vous s'il vous plaît expliquer Class<? extends Enum<?>> e?
Carmageddon
63

Créez un String[]tableau pour les noms et appelez la values()méthode statique qui renvoie toutes les valeurs d'énumération, puis parcourez les valeurs et remplissez le tableau de noms.

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
la source
9
Pourquoi appeler values()13 fois, générant un nouveau tableau à chaque fois, au lieu de mettre le tableau en cache dans une variable locale? Pourquoi utiliser toString (), qui est remplaçable, au lieu de name()?
JB Nizet
@JBNizet heheh, j'ai en fait essayé cela dans mon IDE et je suis paresseux pour créer un tableau d'état, je suppose, hehe, de toute façon je l'ai déjà
édité
2
Vous ne renvoyez toujours pas les noms, mais les valeurs toString ().
JB Nizet
@JBNizet hmm, tbh, je ne sais pas vraiment qu'il y avait une name()méthode jusqu'à maintenant. comment stupide de ma part: P merci de me l'avoir fait savoir :)
PermGenError
1
J'ai accepté cette réponse, mais j'ai soumis une modification qui améliore le code afin qu'il soit plus facile à lire.
Konstantin
14

Voici une solution élégante utilisant Apache Commons Lang 3 :

EnumUtils.getEnumList(State.class)

Bien qu'il renvoie une liste, vous pouvez convertir la liste facilement avec list.toArray()

Sergio Trapiello
la source
5
EnumUtils.getEnumList(enumClass)renvoie les valeurs d'énumération, pas les chaînes. Vous pouvez utiliser EnumUtils.getEnumMap(enumClass).keySet(), mais l'ordre peut être différent.
Dan Halbert
11

Si vous pouvez utiliser Java 8, cela fonctionne bien (alternative à la suggestion de Yura, plus efficace):

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

Avec java 8:

Arrays.stream(MyEnum.values()).map(Enum::name)
                    .collect(Collectors.toList()).toArray();
Yura Galavay
la source
2
Bien que cela fonctionne probablement, cette implémentation est assez inefficace, créant d'abord une ArrayList, ajoutant tous les éléments, puis créant un tableau et copiant tout à nouveau.
Daniel Bimschas
Bientôt, "tout le monde" utilisera des flux pour accomplir les opérations les plus élémentaires ... et ce n'est pas une très bonne idée.
marcolopes
compte tenu du fait que le nombre d'éléments dans les énumérations est généralement assez petit, je pense que la solution de Yura conviendra à de nombreux cas d'utilisation. Naturellement, cela dépendra de la situation spécifique ...
stefan.m
6

Je l'écrirais comme ça

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
la source
3

Quelque chose comme ça ferait:

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

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

  return names;
}

La documentation recommande d'utiliser toString()au lieu de name()dans la plupart des cas , mais vous avez explicitement demandé le nom ici.

Dave Webb
la source
1
Bien que cela n'ait pas particulièrement d'importance, une boucle for régulière offre de meilleures performances qu'une boucle foreach dans cette situation. De plus, il values()est appelé deux fois lorsqu'il ne doit être appelé qu'une seule fois.
FThompson
1
@Vulcan Je pense que les performances ne seraient un problème que si elles étaient exécutées des centaines de milliers de fois. En outre, values()est une méthode générée par le compilateur, donc je suppose qu'elle est assez optimisée. Enfin, je me souviens avoir lu quelque part que les boucles for-each sont plus efficaces que les boucles for standard, incrémentielles, mais là encore, cela n'a pas d'importance .
Konstantin
@Konstantin considérant que la boucle foreach en java est implémentée avec une boucle for standard, où que vous lisiez que les boucles foreach sont toujours plus efficaces est incorrect.
sage88
1
@ sage88 Je faisais référence aux boucles for dans lesquelles vous récupérez des éléments à l'aide d'un index numérique, que vous incrémentez à chaque cycle. Par exemple: for (int i = 0; i < a.length; i++) /* do stuff */;Dans ce cas, les boucles for-each sont , en fait, plus efficaces. Une recherche rapide de SO sur le sujet nous donne ceci: stackoverflow.com/questions/2113216/…
Konstantin
@Konstantin Chaque fois que vous avez une structure de données qui autorise un accès aléatoire, comme c'est le cas avec les valeurs d'énumération, qui renvoie un tableau, une boucle for de style C est plus rapide que d'utiliser une boucle for each. La boucle for each doit générer un itérateur, ce qui la ralentit. Le lien que vous avez publié donne un exemple d'utilisation d'une boucle for standard sur une liste chaînée en utilisant get (i), ce qui est bien sûr pire. Lorsque vous utilisez une structure de données à accès non aléatoire, le pour chaque boucle est plus rapide, mais sur les tableaux, il a une plus grande surcharge. De plus, comme il s'agit d'un tableau primitif, et non d'une ArrayList, il n'y a pas de perte de performances de .size ().
sage88
3

Un autre moyen:

Premier

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

Autre façon

Stream.of(FieldType.values()).map(f -> f.toString()).toArray(String[]::new);
Durgpal Singh
la source
1
Dans ce cas toString()fonctionne, mais dans le cas général, ce n'est pas le cas, car toString()peut être remplacé. Utilisez .name()pour obtenir de manière fiable le nom de l'instance sous forme de chaîne.
Bohème
2

Ma solution, avec manipulation de chaînes (pas la plus rapide, mais compacte):

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
la source
et compatible java7!
Aquarius Power
1

Je le ferais de cette façon (mais je ferais probablement des noms un ensemble non modifiable au lieu d'un tableau):

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
la source
Je ferais aussi quelque chose comme ça si j'avais besoin d'obtenir à plusieurs reprises les noms d'énumérations, mais comme la names()méthode n'est appelée qu'avec parcimonie, je pense que générer un tableau sur place est bien.
Konstantin
1

J'ai le même besoin et j'utilise une méthode générique (à l'intérieur d'une classe ArrayUtils):

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;
}

Et définissez simplement un STATIC à l'intérieur de l'énumération ...

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

Les énumérations Java manquent vraiment les méthodes names () et get (index), elles sont vraiment utiles.

marcolopes
la source
1

la manière ordinaire (jeu de mots):

String[] myStringArray=new String[EMyEnum.values().length];
for(EMyEnum e:EMyEnum.values())myStringArray[e.ordinal()]=e.toString();
Puissance du Verseau
la source
1

J'ai fait un petit test sur la solution de @ Bohemian. Les performances sont meilleures lorsque vous utilisez une boucle naïve à la place.

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);
}
Mandrin
la source
Vous devriez donner les statistiques sur les performances, les gens peuvent alors juger par eux-mêmes si la perte de performance est significative ou non. Je suppose que la plupart des gens n'auront pas 100+ ou 1000+ valeurs pour un Enum.
Rauni Lillemets
1

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

wutzebaer
la source
Qu'est-ce que c'est EnumUtils?
Stephan
@wutzebaer vote à la baisse parce que cette soultion n'est pas complète - elle ne renvoie pas de tableau
Ligne
0

Si vous voulez le plus court, vous pouvez essayer

public static String[] names() {
    String test = Arrays.toString(values());
    return text.substring(1, text.length()-1).split(", ");
}
Peter Lawrey
la source
Pas le plus court :) Voir ma réponse pour un one-liner (qui n'appelle encore qu'une seule vales()fois)
Bohème
0

Juste une pensée: peut-être que vous n'avez pas besoin de créer une méthode pour renvoyer les valeurs de l'énumération sous forme de tableau de chaînes.

Pourquoi avez-vous besoin du tableau de chaînes? Peut-être que vous n'avez besoin de convertir les valeurs que lorsque vous les utilisez, si jamais vous en avez besoin.

Exemples:

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
la source
0

Une autre façon de le faire dans Java 7 ou une version antérieure serait d'utiliser Guava:

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

Essaye ça:

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
la source
0

Vous pouvez mettre des valeurs d'énumération dans une liste de chaînes et les convertir en tableau:

    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.
la source
0

Le moyen le plus simple:

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

Où la catégorie est le Enumnom

Ilja Tarasovs
la source