Utilisation de valeurs Enum comme littéraux de chaîne

389

Quelle est la meilleure façon d'utiliser les valeurs stockées dans une énumération en tant que littéraux de chaîne? Par exemple:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3
}

Plus tard, je pourrais utiliser Mode.mode1pour renvoyer sa représentation sous forme de chaîne mode1. Sans avoir à continuer d'appeler Mode.mode1.toString().

Larry
la source

Réponses:

646

Tu ne peux pas. Je pense que vous avez QUATRE options ici. Tous les quatre offrent une solution mais avec une approche légèrement différente ...

Première option: utilisez la fonction intégrée name()sur une énumération. C'est parfaitement bien si vous n'avez besoin d'aucun format de dénomination spécial.

    String name = Modes.mode1.name(); // Returns the name of this enum constant, exactly as declared in its enum declaration.

Deuxième option: ajoutez des propriétés de substitution à vos énumérations si vous voulez plus de contrôle

public enum Modes {
    mode1 ("Fancy Mode 1"),
    mode2 ("Fancy Mode 2"),
    mode3 ("Fancy Mode 3");

    private final String name;       

    private Modes(String s) {
        name = s;
    }

    public boolean equalsName(String otherName) {
        // (otherName == null) check is not needed because name.equals(null) returns false 
        return name.equals(otherName);
    }

    public String toString() {
       return this.name;
    }
}

Troisième option: utilisez des finales statiques au lieu des énumérations:

public final class Modes {

    public static final String MODE_1 = "Fancy Mode 1";
    public static final String MODE_2 = "Fancy Mode 2";
    public static final String MODE_3 = "Fancy Mode 3";

    private Modes() { }
}

Option quatre: les interfaces ont tous les champs publics, statiques et finaux:

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}
Michael J. Lee
la source
46
Cette réponse est en fait fausse: comme vous pouvez l'appeler .name()Voir: stackoverflow.com/a/6667365/887836
Alex
3
@ kato2 pas correct. La méthode .name () est créée automatiquement par le compilateur
Sean Patrick Floyd
10
JavaDoc: String java.lang.Enum.name () Retourne le nom de cette constante d'énumération, exactement comme déclaré dans sa déclaration d'énumération. La plupart des programmeurs devraient utiliser la méthode toString de préférence à celle-ci, car la méthode toString peut renvoyer un nom plus convivial. Cette méthode est conçue principalement pour une utilisation dans des situations spécialisées où l'exactitude dépend de l'obtention du nom exact, qui ne variera pas d'une version à l'autre. Renvoie: le nom de cette constante d'énumération
SuperRetro
L'awser de @Ryan Stewart nécessite moins de code et moins de code == moins de risques de bugs
Eric
4
N'utilisez pas d'interfaces pour contenir des constantes: Java efficace (3e édition) recommande de "n'utiliser les interfaces que pour définir les types" (point 22).
Olivier Grégoire
481

Chaque énumération possède à la fois une méthode name () et valueOf (String). Le premier renvoie le nom de chaîne de l'énumération, et le second donne la valeur d'énumération dont le nom est la chaîne. C'est comme ça que vous cherchez?

String name = Modes.mode1.name();
Modes mode = Modes.valueOf(name);

Il y a aussi un valueOf statique (classe, chaîne) sur Enum lui-même, vous pouvez donc également utiliser

Modes mode = Enum.valueOf(Modes.class, name);
Ryan Stewart
la source
50
CECI devrait être une RÉPONSE! Utiliser quelque chose comme A ("A") peut être source d'erreurs et c'est un travail supplémentaire insensé!
Firzen
12
@Firzen pas si la valeur de la chaîne peut contenir des espaces ou des tirets, ce qui est le cas some-really-long-string.
ceving
@ceving La question n'est pas bien formulée en ce qui concerne les espaces et les tirets. La question montre un exemple avec trait d'union, mais ne demande pas comment créer un Enum en utilisant des valeurs coupées. Au lieu de cela, la question demande comment obtenir la valeur String sans avoir à appeler toString sans spécifier de valeurs coupées. Cela dit, je pense que cela pourrait être une meilleure réponse s'il était modifié pour mentionner que les valeurs Enum doivent toujours suivre les règles de nommage Java et devraient utiliser quelque chose mentionné dans la réponse acceptée si de tels caractères étaient requis.
Hazok
Je voulais ajouter un lien vers mkyong qui utilise la valueOf(String)méthode en combinaison avec toUpperCase(Locale)pour assurer la conversion des chaînes.
Inconnu Id
2
La raison pour laquelle beaucoup de gens préfèrent l'approche de la propriété à Enum.name () est que la logique basée sur Enum.name () est alors à la merci des noms de valeur. Si le code change à l'avenir, cela pourrait se transformer en un problème non trivial à contourner, car toute la logique précédente interrompra les modifications apportées à l'ensemble de valeurs Enum. Remplacer et utiliser l'approche toString () permet au développeur d'avoir un plus grand contrôle sur les valeurs utilisées, y compris la duplication, les caractères de nom de variable non valides, etc. N'oubliez pas de remplacer également valueOf ().
indivisible
79

Vous pouvez remplacer la toString()méthode pour chaque valeur d'énumération.

Exemple:

public enum Country {

  DE {
    @Override
    public String toString() {
      return "Germany";
    }
  },
  IT {
    @Override
    public String toString() {
      return "Italy";
    }
  },
  US {
    @Override
    public String toString() {
      return "United States";
    }
  }

}

Usage:

public static void main(String[] args) {
  System.out.println(Country.DE); // Germany
  System.out.println(Country.IT); // Italy
  System.out.println(Country.US); // United States
}
Benny Neugebauer
la source
2
J'aime ça. Aucune raison de ne pas utiliser une énumération en tant que classe avec des fonctionnalités supplémentaires telles que l'obtention d'une liste de toutes les valeurs, une chaîne de chaque type, etc.
diegosasw
8
Moche et non réutilisable. Il est préférable de fournir une valeur de chaîne en tant que constructeur pour Country, puis de remplacer la méthode toString () pour l'énumération.
greg7gkb
4
Il s'agit d'une bonne technique lorsque vous disposez d'une énumération assez importante et que vous souhaitez uniquement remplacer les éléments imprimés comme pour un ou deux membres.
Donal Fellows
3
Cela ne change pas du tout. Ne fais pas ça.
sebnukem
1
Cela a du sens pour moi
hanzolo
35

Comme le mentionne Benny Neugebauer, vous pouvez remplacer le toString (). Cependant, au lieu de remplacer la chaîne toString pour chaque champ enum, j'aime plus quelque chose comme ceci:

public enum Country{
    SPAIN("España"),
    ITALY("Italia"),
    PORTUGAL("Portugal");


    private String value;

    Country(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }
}

Vous pouvez également ajouter une méthode statique pour récupérer tous les champs, pour les imprimer tous, etc. Appelez simplement getValue pour obtenir la chaîne associée à chaque élément Enum

diegosasw
la source
30

mode1.name()ou String.valueOf(mode1). Ça ne va pas mieux que ça, j'ai peur

Sean Patrick Floyd
la source
21
public enum Modes {
  MODE1("Mode1"),
  MODE2("Mode2"),
  MODE3("Mode3");

 private String value;
 public String getValue() {
    return value;
   }
 private Modes(String value) {
  this.value = value;
 } 
}

vous pouvez effectuer un appel comme ci-dessous où vous voulez obtenir la valeur sous forme de chaîne à partir de l'énumération.

Modes.MODE1.getvalue();

Cela renverra "Mode1" sous forme de chaîne.

vamsi
la source
6

Vous pouvez utiliser Mode.mode1.name()mais vous n'avez souvent pas besoin de le faire.

Mode mode =
System.out.println("The mode is "+mode);
Peter Lawrey
la source
6
Il convient de noter que l'opérateur + appellera toString () sur l'énumération, et non name (). Et toString () peut être surchargé pour retourner autre chose que le nom (même si ce n'est pas souhaitable)
JB Nizet
1
Les deux name()et toString()peuvent être remplacés, mais j'espère que cela sera clair à la lecture du code pour enumsi cela se produit.
Peter Lawrey
9
No. name () est final et renvoie toujours le nom de l'énumération tel que déclaré dans sa déclaration d'énumération.
JB Nizet
1
@JB Nizet, vous avez raison. name()est final. Merci de m'avoir corrigé. :)
Peter Lawrey
6

Pour autant que je sache, la seule façon d'obtenir le nom serait

Mode.mode1.name();

Si vous en avez vraiment besoin de cette façon, cependant, vous pouvez faire:

public enum Modes {
    mode1 ("Mode1"),
    mode2 ("Mode2"),
    mode3 ("Mode3");

    private String name;       

    private Modes(String s) {
        name = s;
    }
}
Jake Roussel
la source
1
Mais dans ce cas, Mode.mode1n'est toujours pas de type String.
Larry
Ah oui. Vous auriez besoin d'une méthode getName (), ce qui va à l'encontre du but, donc non, vous ne pouvez pas le faire.
Jake Roussel
"nom" est un mauvais nom de champ, c'est un champ standard de enum.
Wooff
6

Pour mes énumérations, je n'aime pas vraiment penser qu'elles soient allouées avec 1 chaîne chacune. C'est ainsi que j'implémente une méthode toString () sur les énumérations.

enum Animal
{
    DOG, CAT, BIRD;
    public String toString(){
        switch (this) {
            case DOG: return "Dog";
            case CAT: return "Cat";
            case BIRD: return "Bird";
        }
        return null;
    }
}
Ethan
la source
1
Lancer une exception d'exécution serait mieux au lieu de renvoyer null car il devrait être du code inaccessible?
loue
Le returnest redondant, car l'activation des énumérations avec toutes les énumérations se termine.
Danon
5

Vous pouvez simplement utiliser:

""+ Modes.mode1
Copain
la source
Je ne suis pas sûr à 100%, mais pour autant que je sache, ce casting n'est pas nécessaire, n'est-ce pas? La concaténation d'une chaîne vide avec une autre variable devrait automatiquement appeler une conversion, ou y a-t-il des exceptions à cette règle?
Inconnu Id
1
Vous avez raison, la bonne version devrait l'être "" + Modes.mode1. J'ai fixé la réponse
Buddy
La réponse d'EB profite également en rappelant l'idiome de python ''.join()
anthropic android
5

ma solution à votre problème!

import java.util.HashMap;
import java.util.Map;

public enum MapEnumSample {
    Mustang("One of the fastest cars in the world!"), 
    Mercedes("One of the most beautiful cars in the world!"), 
    Ferrari("Ferrari or Mercedes, which one is the best?");

    private final String description;
    private static Map<String, String> enumMap;

    private MapEnumSample(String description) {
        this.description = description;
    }

    public String getEnumValue() {
        return description;
    }

    public static String getEnumKey(String name) {
        if (enumMap == null) {
            initializeMap();
        }
        return enumMap.get(name);
    }

    private static Map<String, String> initializeMap() {
        enumMap = new HashMap<String, String>();
        for (MapEnumSample access : MapEnumSample.values()) {
            enumMap.put(access.getEnumValue(), access.toString());
        }
        return enumMap;
    }

    public static void main(String[] args) {

        // getting value from Description
        System.out.println(MapEnumSample.getEnumKey("One of the fastest cars in the world!"));

        // getting value from Constant
        System.out.println(MapEnumSample.Mustang.getEnumValue());

        System.out.println(MapEnumSample.getEnumKey("One of the most beautiful cars in the world!"));
        System.out.println(MapEnumSample.Mercedes.getEnumValue());

        // doesnt exist in Enum
        System.out.println("Mustang or Mercedes, which one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Mustang or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mustang, which one is the best?") + " is the best!.");

        // exists in Enum
        System.out.println("Ferrari or Mercedes, wich one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") + " is the best!");

    }
}
Renan Galdino da Silva
la source
Il semble que le problème du PO ait été résolu il y a 4 ans, mais bienvenue dans StackOverflow :)
TMD
1
Merci, juste pour aider quelqu'un comme moi, à la recherche de réponses plus objectives à d'anciens problèmes :)
Renan Galdino da Silva
3

Enum est juste une classe un peu spéciale. Les énumérations peuvent stocker des champs supplémentaires, implémenter des méthodes, etc. Par exemple

public enum Modes {
    mode1('a'),
    mode2('b'),
    mode3('c'),
    ;
    char c;

    private Modes(char c) {
        this.c = c;
    }
    public char character() {
        return c;
    }
}

Vous pouvez maintenant dire:

System.out.println(Modes.mode1.character())

et voir la sortie: a

AlexR
la source
3
package com.common.test;

public  enum Days {


    monday(1,"Monday"),tuesday(2,"Tuesday"),wednesday(3,"Wednesday"),
    thrusday(4,"Thrusday"),friday(5,"Friday"),saturday(6,"Saturday"),sunday(7,"Sunday");

    private int id;
    private String desc;


    Days(int id,String desc){
        this.id=id;
        this.desc=desc;
    }

    public static String getDay(int id){

        for (Days day : Days.values()) {
            if (day.getId() == id) {
                return day.getDesc();
            }
        }
        return null;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }



};

la source
1
Pouvez-vous expliquer comment cela résoudrait le problème?
Phani
vous pouvez appeler cette énumération n'importe où en utilisant cette ligne: int id = 1; Chaîne dayName = Days.getDay (id); , passez ici id. il renverra la description de cet identifiant qui est «mardi»
2

Cette méthode devrait fonctionner avec enum:

public enum MyEnum {
    VALUE1,
    VALUE2,
    VALUE3;

    public int getValue() {
        return this.ordinal();
    }

    public static DataType forValue(int value) {
        return values()[value];
    }

    public String toString() {
        return forValue(getValue()).name();
    }
}
Caner
la source
2
public enum Environment
{
    PROD("https://prod.domain.com:1088/"),
    SIT("https://sit.domain.com:2019/"),
    CIT("https://cit.domain.com:8080/"),
    DEV("https://dev.domain.com:21323/");

    private String url;

    Environment(String envUrl) {
        this.url = envUrl;
    }

    public String getUrl() {
        return url;
    }
}

String prodUrl = Environment.PROD.getUrl();

Il imprimera:

https://prod.domain.com:1088/

Cette conception pour les constantes de chaîne enum fonctionne dans la plupart des cas.

lokesh
la source
0

après de nombreux essais, je suis venu avec cette solution

public static enum Operation {

    Addition, Subtraction, Multiplication, Division,;

    public String getUserFriendlyString() {
        if (this==Addition) {
            return " + ";
        } else if (this==Subtraction) {
            return " - ";
        } else if (this==Multiplication) {
            return " * ";
        } else if (this==Division) {
            return " / ";
        }
        return "undefined";
       }
}
Basheer AL-MOMANI
la source
0

Vous pouvez essayer ceci:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    public String toString(){
        switch(this) {
            case some-really-long-string:
                return "some-really-long-string";
            case mode2:
                return "mode2";
            default: return "undefined";
        }
    }

}

Kamil Naja
la source
0

j'ai trouvé que celui-ci est plus facile pour éviter les erreurs de type:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    String str;

    Modes(){
        this.str = super.name();
    }

    @Override
    @NonNull
    public String toString() {
        return str;
    }

cependant - cela peut fonctionner lorsque vous devez utiliser une chaîne sur un journal / println ou chaque fois que java compile automatiquement la méthode toString (), mais sur une ligne de code comme celle-ci ->

// sample method that require (string,value)
intent.putExtra(Modes.mode1 ,shareElement.getMode()); // java error
// first argument enum does not return value

à la place, comme mentionné ci-dessus, vous devrez toujours étendre l'énumération et l'utiliser .name() dans les cas comme celui-ci:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
ItzikH
la source