La meilleure façon de créer une énumération de chaînes?

364

Quelle est la meilleure façon d'avoir un enumtype représentant un ensemble de chaînes?

J'ai essayé ceci:

enum Strings{
   STRING_ONE("ONE"), STRING_TWO("TWO")
}

Comment puis-je les utiliser comme Strings?

Dori
la source

Réponses:

605

Je ne sais pas ce que vous voulez faire, mais c'est ainsi que j'ai traduit votre exemple de code ...

package test;

/**
 * @author The Elite Gentleman
 *
 */
public enum Strings {
    STRING_ONE("ONE"),
    STRING_TWO("TWO")
    ;

    private final String text;

    /**
     * @param text
     */
    Strings(final String text) {
        this.text = text;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return text;
    }
}

Vous pouvez également créer une méthode getter pour text .

Vous pouvez maintenant faire Strings.STRING_ONE.toString();

Buhake Sindi
la source
3
Je ne sais pas si c'est une exigence du compilateur, mais private String textdevrait être définitive.
Jonathan
7
@ Tomás Narros Oui, vous pouvez toujours lui affecter dans le constructeur, tant que vous ne lui donnez pas de valeur lorsque vous le déclarez final.
Jonathan
28
@The Elite Gentleman Ce serait mauvais si la valeur d'une constante enum changeait pendant l'exécution, donc même si elle n'est pas requise, ce finalserait mieux.
Jonathan
8
N'oubliez pas que les énumérations ne peuvent pas être construites avec newle constructeur private. Essentiellement, la création d'objets est interdite et finaln'est pas vraiment nécessaire dans ce cas.
Buhake Sindi
6
@BuhakeSindi: c'est vrai, mais accidentellement, on peut être enclin à mettre un setText(String)sur l'énumération et cela peut déclencher l'enfer :) finalgenre de documents votre intention que ce soit une constante avec le support du compilateur. Si vous deviez utiliser des Stringconstantes, vous ne le déclareriez pas public static String, non?
TWiStErRob
104

Valeurs de chaîne personnalisées pour Enum

depuis http://javahowto.blogspot.com/2006/10/custom-string-values-for-enum.html

La valeur de chaîne par défaut pour java enum est sa valeur nominale ou le nom de l'élément. Cependant, vous pouvez personnaliser la valeur de chaîne en remplaçant la méthode toString (). Par exemple,

public enum MyType {
  ONE {
      public String toString() {
          return "this is one";
      }
  },

  TWO {
      public String toString() {
          return "this is two";
      }
  }
}

L'exécution du code de test suivant produira ceci:

public class EnumTest {
  public static void main(String[] args) {
      System.out.println(MyType.ONE);
      System.out.println(MyType.TWO);
  }
}


this is one
this is two
vaichidrewar
la source
16
Ce n'est pas un moyen efficace de le faire. Cela crée une nouvelle classe personnalisée pour chaque valeur de l'énumération. Dans l'exemple ci-dessus, vous verrez les éléments suivants dans le binrépertoire: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class qui s'additionnera très rapidement. Il vaut mieux le faire comme réponse attendue, en passant des valeurs au constructeur enum. En fait, je suis en désaccord avec la dérogation toString(); Je pense qu'il est préférable d'utiliser un getter explicite, getKey()car le remplacement toString()peut être inattendu par un autre utilisateur de l'énumération.
Matt Quigley
totalement d'accord avec @MattQuigley. Cela encourage les utilisateurs à utiliser toString pour des choses pour lesquelles il ne devrait pas être utilisé. Si vous avez besoin d'une étiquette, vous préférez ajouter un attribut d'étiquette
Sebastien Lorber
De plus, il n'y a aucun moyen de faire l'inverse (d'une chaîne à l'objet enum) qui sera probablement nécessaire à un moment donné.
Adrian Smith
remplacer toString n'affecte pas valueOf (), n'est-ce pas?
Dmitriusan
69

Utilisez sa name()méthode:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.ONE.name());
    }
}

enum Strings {
    ONE, TWO, THREE
}

rendements ONE.

Bart Kiers
la source
17
Oui, mais Strings.STRING_ONE.name()donne "STRING_ONE", pas "ONE". Ce n'est tout simplement pas une bonne réponse. Vous ne pouvez pas avoir de chaîne qui ne serait pas un identifiant Java valide, etc.
Mark Peters
2
@Mark, c'est vrai, il ne peut gérer aucun caractère. Si l'OP ne veut qu'un seul caractère, cette solution est plus simple que la suggestion The Elite Gentleman. Mais en effet: si la plage de caractères dépasse ceux qu'un identifiant Java valide peut avoir, ce n'est pas possible. Bon point.
Bart Kiers
Il est très raisonnable d'avoir une convention de dénomination interne pour une énumération différente de ce que l'on voudrait montrer avec toString () (surtout si un utilisateur voit la sortie), donc je ne pense pas que ce soit tout à fait ce que l'OP était à la recherche de.
Michael McGowan
17
Le résultat de name()peut être affecté par un programme d'obscurcisseur. J'ai rencontré un problème similaire il y a quelque temps. Par exemple, avec Proguard, vous devez contourner ce problème. Voir Traitement des classes d'énumération
noisecapella
C'est excellent. Fonctionne avec des valeurs comme: var_name, var_superlong_but_not_toooooo_long_name, même etc (sans les points triples)
19

Soit définissez le nom d'énumération comme étant la chaîne que vous souhaitez, soit, plus généralement, vous pouvez associer des attributs arbitraires à vos valeurs d'énumération:

enum Strings {
   STRING_ONE("ONE"), STRING_TWO("TWO");
   private final String stringValue;
   Strings(final String s) { stringValue = s; }
   public String toString() { return stringValue; }
   // further methods, attributes, etc.
}

Il est important d'avoir les constantes en haut et les méthodes / attributs en bas.

Adrian Smith
la source
Et aussi d'avoir un constructeur privé .
Buhake Sindi
1
Les constructeurs enum sont privés par défaut et ne nécessitent aucun modificateur d'accès. Mais c'est un bon point sur les modificateurs d'accès en général, j'ai mis à jour mon code pour les ajouter à l'attribut et à l'accesseur.
Adrian Smith
15

Selon ce que vous entendez par «les utiliser comme chaînes», vous ne voudrez peut-être pas utiliser une énumération ici. Dans la plupart des cas, la solution proposée par The Elite Gentleman vous permettra de les utiliser via leurs méthodes toString, par exemple dans System.out.println(STRING_ONE)ou String s = "Hello "+STRING_TWO, mais lorsque vous avez vraiment besoin de Strings (par exemple STRING_ONE.toLowerCase()), vous préférerez peut-être les définir comme constantes:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}
hd42
la source
5
en fait c'est ce que j'essaye d'éviter ...!
Dori
En fait, s'ils veulent aussi la toLowerCase()solution, ils peuvent y aller Strings.STRING_TWO.toString().toLowerCase().
Buhake Sindi
Bien sûr, mais cela ne les utilise pas comme des chaînes comme je l'ai interprété. Comme Rrackham ne semble pas exiger cette utilisation, il devrait bien sûr utiliser la solution d'énumération proposée.
hd42
6
Vous ne devez pas utiliser interfaceà la place d'une finalclasse avec privateconstructeur. C'est une pratique découragée.
Aleks N.
1
@mils, les solutions utilisant des énumérations fonctionnent aussi bien dans un commutateur. Je suggérerais cette solution uniquement si des chaînes sont nécessaires directement.
hd42
8

Vous pouvez l'utiliser pour la chaîne Enum

public enum EnumTest {
    NAME_ONE("Name 1"),
    NAME_TWO("Name 2");

    private final String name;

    /**
     * @param name
     */
    private EnumTest(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Et appel de la méthode principale

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}
Shohel Rana
la source
5

Si vous ne souhaitez pas utiliser de constructeurs et que vous souhaitez avoir un nom spécial pour la méthode, essayez-le comme suit:

public enum MyType {
  ONE {
      public String getDescription() {
          return "this is one";
      }
  },    
  TWO {
      public String getDescription() {
          return "this is two";
      }
  };

  public abstract String getDescription();
}

Je soupçonne que c'est la solution la plus rapide . Il n'est pas nécessaire d'utiliser des variables finales .

Adam111p
la source
mais avec celui-ci, vous devez toujours appeler getDescription () dont la personne qui demande veut appeler ONE ou y accéder en tant que constante.
kinsley kajiva
Je préfère ça. Que se passera-t-il s'il doit accepter plus d'informations? Avec cette solution, ajoutez simplement des méthodes abstraites protégées et remplacez-la. Plus sur aucun besoin de remplacer la méthode toString (). C'est propre et peut être accepté comme la meilleure réponse.
Arundev
0

Obtenez et définissez avec les valeurs par défaut.

public enum Status {

    STATUS_A("Status A"),  STATUS_B("Status B"),

    private String status;

    Status(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}
Pravin
la source