with values type enum define data java design-patterns enums language-design

values - ¿Ventajas de la enumeración de Java sobre el viejo patrón "Typesafe Enum"?



java enum string (7)

Ahora en JDK1.5 +, la forma "oficial" es obviamente usar enum :

public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name; private Suit(String name) { this.name = name; } }

En realidad, es más como

public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES; }

porque las enumeraciones ya proporcionan un método de name() . Además, proporcionan un método ordinal() que permite estructuras de datos eficientes como EnumSet y EnumMap , implementan Serializable , anulan toString , proporcionan values() y valueOf(String name) . Se pueden usar en una declaración de cambio de tipo seguro, y son singletons.

En Java anterior a JDK1.5, el patrón "Typesafe Enum" era la forma habitual de implementar un tipo que solo puede tomar un número finito de valores:

public class Suit { private final String name; public static final Suit CLUBS =new Suit("clubs"); public static final Suit DIAMONDS =new Suit("diamonds"); public static final Suit HEARTS =new Suit("hearts"); public static final Suit SPADES =new Suit("spades"); private Suit(String name){ this.name =name; } public String toString(){ return name; } }

(ver, por ejemplo, el Elemento 21 del Java Efectivo de Bloch).

Ahora en JDK1.5 +, la forma "oficial" es obviamente usar enum :

public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name; private Suit(String name) { this.name = name; } }

Obviamente, la sintaxis es un poco más clara y concisa (no es necesario definir explícitamente campos para los valores, adecuado para toString() provisto), pero hasta ahora, enum parece mucho al patrón Typesafe Enum.

Otras diferencias que conozco:

  • las enumeraciones proporcionan automáticamente un método de values()
  • las enumeraciones se pueden usar en switch() (y el compilador incluso comprueba que no se olvide un valor)

Pero todo esto parece poco más que azúcar sintáctico, incluso con algunas limitaciones (por ejemplo, enum siempre hereda de java.lang.Enum y no se puede subclasificar).

¿Hay otros beneficios más fundamentales que proporciona enum que no se pudieron realizar con el patrón Typesafe Enum?


El azúcar sintáctico solo vale su sal :-P Después de todo, eso es para (): también lo es.

Pero en serio, el hecho de tener nombre () y ordinal () automáticamente, enumerarlos, usarlos en switch (), para adjuntar valores adicionales a ellos, son buenos argumentos para ellos: evita la gran cantidad de código repetitivo .

La alternativa perezosa tradicional, que usa ints, no es segura y es mucho más limitada. Un inconveniente de las enumeraciones sobre esta alternativa es que ya no son livianas.


En adición:

Las enumeraciones de JDK5 se pueden usar fácilmente en las sentencias de conmutadores con una buena compatibilidad con IDE

Suit suit = ...; switch (suit) { case SPADES: System.out.println("Motorhead!"); break; default: System.out.println("Boring .."); }


Por supuesto, hay muchas ventajas que otras personas mencionarán aquí como respuestas. Lo más importante es que puedes escribir enums muy rápido y hacen muchas cosas como implementar Serializable , Comparable , equals() , toString() , hashCode() , etc., que no hashCode() en tu enumeración.

Pero puedo mostrarte un serio inconveniente de enum (IMO). No solo no puedes subclasificarlos a voluntad, sino que no puedes equiparlos con un parámetro genérico. Cuando podrías escribir esto:

// A model class for SQL data types and their mapping to Java types public class DataType<T> { private final String name; private final Class<T> type; public static final DataType<Integer> INT = new DataType<Integer>("int", Integer.class); public static final DataType<Integer> INT4 = new DataType<Integer>("int4", Integer.class); public static final DataType<Integer> INTEGER = new DataType<Integer>("integer", Integer.class); public static final DataType<Long> BIGINT = new DataType<Long>("bigint", Long.class); private DataType(String name, Class<T> type){ this.name = name; this.type = type; } // Returns T. I find this often very useful! public T parse(String string) throws Exception { // [...] } } class Utility { // Enums equipped with generic types... public static <T> T doStuff(DataType<T> type) { return ... } }

Esto no es posible con una enumeración:

// This can''t be done public enum DataType<T> { // Neither can this... INT<Integer>("int", Integer.class), INT4<Integer>("int4", Integer.class), // [...] }


Su implementación enum segura de tipo es un poco simplificada. Cuando maneje la serialización, será mucho más complicado.

Java enum s resuelve el problema con la serialización / deserialización. se garantiza que las enum son únicas y puedes compararlas con == operator.

Lea los capítulos correspondientes en Effective Java 2nd Edition (sobre el uso de enumeraciones en lugar de singletons, sobre el uso de EnumSet s, etc.).


EnumSet y EnumMap son estructuras de datos personalizadas que se basan en las características específicas de las enumeraciones. Tienen funciones adicionales prácticas y son extremadamente rápidos. No hay un equivalente (al menos no con una elegancia de uso equivalente, ver comentarios) para ellos sin enumeraciones.


  • "no se puede subclasificar" no es una restricción. Es una de las grandes ventajas: ¡garantiza que siempre haya exactamente el conjunto de valores definido en la enum y nada más!
  • enum maneja correctamente la serialización. También puede hacerlo con enumeraciones seguras de tipo, pero a menudo se olvida (o simplemente no se conoce). Esto asegura que e1.equals(e2) siempre implica e1 == e2 para dos valores enum e1 y e2 (y viceversa, que probablemente sea más importante).
  • Existen estructuras de datos livianas específicas que manejan las enumeraciones: EnumSet y EnumMap (robadas de esta respuesta )