2008-10-27 22 views
21

Dada la siguiente enumeración de java:Cómo convertir el resultado de cadena de enum con el reemplazado toString() a 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"; 
     } 
    }, 

} 

¿Hay alguna manera de convertir un valor de cadena de "18 - 23" para el valor de enumeración correspondiente decir AgeRange.A18TO23?

Gracias!

Respuesta

30

La forma mejor y más sencilla de hacerlo es la siguiente:

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

Luego solo necesita invocar el método getByValue() con la entrada String en eso.

+1

Estoy de acuerdo en que es bueno poner el valor en el constructor.Para enumeraciones muy grandes (y realmente tendrían que ser bastante grandes) tendría sentido usar un mapa. Yo personalmente regresaría desde el interior del ciclo, pero nunca he sido fanático de "regresar de un lugar sin importar la legibilidad" :) –

+0

Otro punto: sería mejor usar EnumSet.allOf en su lugar de AgeRange.values ​​() ya que de lo contrario, usted crea una nueva matriz para cada llamada. –

+0

Estoy de acuerdo con usted Jon Skeet :) Cambiando ... – sakana

7

Siempre puede crear un mapa de cadena a valor, hágalo estáticamente, de modo que solo necesita asignarlo una vez, suponiendo que la cadena devuelta se mantiene igual a lo largo del tiempo. No hay nada incorporado, hasta donde yo sé.

+0

Esta es una forma mucho mejor de manejar esto. El mapa se crea cuando la enumeración es, y opera mucho más rápido que iterar una matriz. –

+0

Estoy considerando este método también, pero tengo solo alrededor de 15 valores en esta enumeración. ¿Sigue siendo más eficiente crear un mapa? – Walter

+0

Probablemente no, para ser honesto. Las tablas Hash son geniales para grandes cantidades de datos, pero sospecho que comparar 15 valores (en el peor de los casos) será tan rápido como obtener el código hash, encontrar el cubo correcto, etc. –

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

¿O algo así? Simplemente tecleé, no he corrido a través de un compilador. Perdonar (comentar) errores tipográficos ...

O use una lógica como esta para construir un mapa una vez. Evite la iteración en tiempo de ejecución. Buena idea, Jon.

2

La clase anula "toString()" - por lo tanto, para obtener la operación inversa, debe sobrescribir valueOf() para traducir la salida de toString() a los valores Enum.

public enum AgeRange { 

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

    . 
    . 
    . 
} 

Alerta comprador - sin compilar y no probado ...

El mecanismo para toString() y valueOf() es una parte documentada de la API

+0

¿Debería ese segundo ser el método valueOf? – iny

+0

[iny] es absolutamente correcto - editado para reflejar. –

+2

-1 Si no me equivoco, el consejo sobre valueOf aquí es ... incorrecto, ser amable ;-). 'valueOf()' es estático y no se usa en el cuerpo de un valor de enumeración particular. E incluso cuando todo esto se solucione, la implementación "correcta" sería incorrecta, ya que el compilador no permite una sustitución estática en 'static public Value of (String)'. La solución común es simplemente no usar 'valueOf' - use un nombre diferente. –

0

¿Podría intentar algo como lo siguiente?

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

O, como otros sugirieron, utilizando un enfoque de almacenamiento en caché:

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

De acuerdo con java efectiva (2ª ed) Artículo 30, puede ser (que es mucho más rápido que el bucle)

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