2008-10-27 13 views
21

Étant donné l'ENUM java suivante:Comment faire pour convertir le résultat de chaîne de enum avec overrenced toString() retour à enum?

public enum AgeRange { 

    A18TO23 { 
     public String toString() {   
      return "18 - 23"; 
     } 
    }, 
    A24TO29 { 
     public String toString() {   
      return "24 - 29"; 
     } 
    }, 
    A30TO35 { 
     public String toString() {   
      return "30 - 35"; 
     } 
    }, 

} 

Est-il possible de convertir une valeur de chaîne de « 18 - 23 » à la valeur correspondante ENUM à savoir AgeRange.A18TO23?

Merci!

Répondre

30

La meilleure et la plus simple façon de le faire est comme documenté ceci:

public enum AgeRange { 
    A18TO23 ("18-23"), 
    A24TO29 ("24-29"), 
    A30TO35("30-35"); 

    private String value; 

    AgeRange(String value){ 
     this.value = value; 
    } 

    public String toString(){ 
     return value; 
    } 

    public static AgeRange getByValue(String value){ 
     for (final AgeRange element : EnumSet.allOf(AgeRange.class)) { 
      if (element.toString().equals(value)) { 
       return element; 
      } 
     } 
     return null; 
    } 
} 

Ensuite, vous avez juste besoin d'appeler la méthode getByValue() avec l'entrée String dedans.

+1

Je suis d'accord que c'est bien de mettre la valeur dans le constructeur.Pour de très gros enums (et ils devraient vraiment être assez gros), il serait logique d'utiliser une carte. Je reviendrais personnellement de l'intérieur de la boucle, mais je n'ai jamais été fan de "retour d'un endroit sans tenir compte de la lisibilité" :) –

+0

Un autre point - il serait préférable d'utiliser EnumSet.allOf à la place de AgeRange.values ​​() sinon vous créez un nouveau tableau pour chaque appel. –

+0

Je suis d'accord avec vous Jon Skeet :) Changer ... – sakana

7

Vous pouvez toujours créer une carte à partir d'une chaîne à une valeur - faites-le de façon statique, vous n'avez donc besoin de la mapper qu'une seule fois, en supposant que la chaîne retournée reste la même avec le temps. Il n'y a rien d'intégré autant que je sache.

+0

Ceci est une bien meilleure façon de gérer cela. La carte est ensuite créée lorsque l'énumération est, et fonctionne beaucoup plus rapidement que l'itération d'un tableau. –

+0

Je considère également cette méthode, mais je n'ai qu'environ 15 valeurs dans cette énumération. Est-il encore plus efficace de créer une carte? – Walter

+0

Probablement pas, pour être honnête. Les tableaux de hachage sont parfaits pour de grandes quantités de données, mais je soupçonne que comparer 15 valeurs (au pire) sera aussi rapide que d'obtenir le code, trouver le bon seau, etc. –

2
for (AgeRange ar: EnumSet.allOf(AgeRange)) { 
    if (ar.toString().equals(inString)) { 
     myAnswer = ar; 
     break; 
    } 
} 

Ou quelque chose comme ça? Juste saisi, n'a pas exécuté un compilateur. Pardonner (commenter) les fautes de frappe ...

Ou utilisez une logique comme celle-ci pour créer une carte une fois. Évitez les itérations lors de l'exécution. Bonne idée, Jon.

2

La classe remplace "toString()". Par conséquent, pour obtenir l'opération inverse, vous devez remplacer valueOf() pour convertir la sortie toString() en valeurs Enum.

public enum AgeRange { 

    A18TO23 { 
     public String toString() {   
       return "18 - 23"; 
     } 
     public AgeRange valueOf (Class enumClass, String name) { 
       return A18T023 
     } 
    }, 

    . 
    . 
    . 
} 

Acheteur méfiez-vous - et non testé ... décompilé

Le mécanisme de toString() et valueOf() est une partie de la API

+0

Devrait-on utiliser la méthode valueOf? – iny

+0

[iny] est absolument correct - édité pour refléter. –

+2

-1 Si je ne me trompe pas, le conseil sur valueOf ici est ... mauvais, pour être gentil ;-). 'valueOf()' est statique et inutile dans le corps d'une valeur enum particulière. Et même une fois que tout ceci est corrigé, l'implémentation "correcte" serait fausse, dans la mesure où le compilateur n'autorise pas un override statique sur 'static public valueOf (String)'. La solution courante consiste simplement à ne pas utiliser 'valueOf' - utilisez un nom différent. –

0

Vous pourriez essayer quelque chose comme ce qui suit?

static AgeRange fromString(String range) { 
    for (AgeRange ageRange : values()) { 
     if (range.equals(ageRange.toString())) { 
      return ageRange; 
     } 
    } 
    return null; 
} 

Ou, comme d'autres ont suggéré, en utilisant une approche de mise en cache:

private static Map<String, AgeRange> map; 

private static synchronized void registerAgeRange(AgeRange ageRange) { 
    if (map == null) { 
     map = new HashMap<String, AgeRange>(); 
    } 
    map.put(ageRange.toString(), ageRange); 
} 

AgeRange() { 
    registerAgeRange(this); 
} 

static AgeRange fromString(String range) { 
    return map.get(range); 
} 
4

Selon l'article 30 java efficace (2nd ed), il peut être (il est beaucoup plus rapide que la boucle)

public enum AgeRange { 
     A18TO23("18-23"), 
     A24TO29("24-29"), 
     A30TO35("30-35"); 

     private final String value; 

     AgeRange(String value){ 
      this.value = value; 
     } 

     @Override public String toString(){ 
      return value; 
     } 

     private static final Map<String, AgeRange> stringToEnum = 
      new HashMap<String, AgeRange>(); 

     static { 
      for (AgeRange r : values()) { 
       stringToEnum.put(r.toString(), r); 
      } 
     } 

     public static AgeRange getByValue(String value){ 
      return stringToEnum.get(value); 
     } 
}