[Java] ¿Qué son las enumeraciones y por qué son útiles?


Answers

¿Por qué utilizar cualquier función de lenguaje de programación? La razón por la que tenemos idiomas es para

  1. Los programadores expresan algoritmos de forma eficiente y correcta en un formulario que las computadoras pueden usar.
  2. Los encargados de mantenimiento entienden los algoritmos que otros han escrito y hacen los cambios correctamente .

Los enum mejoran la probabilidad de corrección y legibilidad sin escribir un montón de repetición. Si está dispuesto a escribir un borrador, entonces puede "simular" enumeraciones:

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

Ahora puedes escribir:

Color trafficLightColor = Color.RED;

La repetición anterior tiene el mismo efecto que

public enum Color { RED, AMBER, GREEN };

Ambos proporcionan el mismo nivel de comprobación de la ayuda del compilador. Boilerplate es simplemente más tipeo. Pero guardar mucha escritura hace que el programador sea más eficiente (ver 1), por lo que es una función que vale la pena.

Vale la pena al menos una razón más:

Cambiar declaraciones

Una cosa que la simulación de enum static final anterior no le da es buenos casos de switch . Para los tipos de enumeración, el modificador de Java usa el tipo de su variable para inferir el alcance de los casos de enumeración, por lo que para el enum Color arriba simplemente necesita decir:

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Tenga en cuenta que no es Color.RED en los casos. Si no usa enum, la única forma de usar cantidades con nombre con el switch es algo como:

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

Pero ahora una variable para mantener un color debe tener tipo int . La buena comprobación del compilador de la enumeración y la simulación static final está. No feliz.

Un compromiso es usar un miembro de valor escalar en la simulación:

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

Ahora:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

Pero tenga en cuenta, incluso más repetitivo!

Usando una enumeración como singleton

De la repetición anterior se puede ver por qué una enumeración proporciona una forma de implementar un singleton. En lugar de escribir:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

y luego accediéndolo con

SingletonClass.INSTANCE

solo podemos decir

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

que nos da lo mismo. Podemos salimos con la nuestra porque las enumeraciones de Java se implementan como clases completas con solo un poco de azúcar sintáctico salpicado en la parte superior. Esto es, de nuevo, menos repetitivo, pero no es obvio, a menos que el idioma te sea familiar. También me desagrada el hecho de que obtienes las diversas funciones enum, aunque no tienen mucho sentido para el singleton: ord y values , etc. (En realidad, hay una simulación más complicada donde Color extends Integer que funcionará con switch, pero es tan es complicado que muestre aún más claramente por qué enum es una mejor idea).

Hilo de seguridad

La seguridad del subproceso es un problema potencial solo cuando los singletons se crean perezosamente sin bloqueo.

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

Si muchos hilos llaman a getInstance simultáneamente mientras que INSTANCE todavía es nulo, se puede crear cualquier cantidad de instancias. Esto es malo. La única solución es agregar acceso synchronized para proteger la variable INSTANCE .

Sin embargo, el código static final anterior no tiene este problema. Crea la instancia con entusiasmo en el tiempo de carga de la clase. La carga de clases está sincronizada.

El enum singleton es efectivamente flojo porque no se inicializa hasta el primer uso. La inicialización de Java también está sincronizada, por lo que varios subprocesos no pueden inicializar más de una instancia de INSTANCE . Obtendrá un singleton perezosamente inicializado con muy poco código. Lo único negativo es la sintaxis bastante oscura. Necesita saber la expresión idiomática o comprender a fondo cómo funciona la carga de clases y la inicialización para saber qué está sucediendo.

Question

Hoy hojeé algunas preguntas en este sitio y encontré una mención de una enum se utiliza en el patrón de singleton sobre supuestos beneficios de seguridad de los hilos para dicha solución.

Nunca he usado enum s y he estado programando en Java durante más de dos años. Y aparentemente cambiaron mucho. Ahora incluso hacen pleno apoyo de OOP dentro de ellos mismos.

Ahora, ¿por qué y para qué debería usar Enum en la programación diaria?




Es útil saber que las enums son como las otras clases con campos Constant y un private constructor .

Por ejemplo,

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

El compilador lo compila de la siguiente manera;

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}



En cuanto a mí para hacer que el código sea legible en el futuro, el caso de enumeración aplyable más útil se representa en el siguiente fragmento:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};



Enum? ¿Por qué debería ser usado? Creo que se comprende mejor cuándo lo usarás. Tengo la misma experiencia.

Supongamos que tiene una operación de creación, eliminación, edición y lectura de base de datos.

Ahora si crea una operación enum:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

Ahora, puedes declarar algo como:

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

Entonces puedes usarlo de muchas maneras. Siempre es bueno tener enum para cosas específicas ya que la operación de la base de datos en el ejemplo anterior se puede controlar al verificar la operación actual . Quizás uno puede decir que esto se puede lograr con variables y valores enteros también. Pero creo que Enum es una forma más segura y de programador.

Otra cosa: creo que a todos los programadores les encantan los booleanos , ¿no? Porque puede almacenar solo dos valores, dos valores específicos. Así que se puede pensar que Enum tiene el mismo tipo de instalaciones donde el usuario definirá cuántos y qué tipo de valor almacenará, solo de una manera ligeramente diferente. :)




Algo que ninguna de las otras respuestas ha cubierto que haga que las enumeraciones particularmente poderosas sean la capacidad de tener métodos de plantilla . Los métodos pueden ser parte de la enumeración base y anulados por cada tipo. Y, con el comportamiento asociado a la enumeración, a menudo elimina la necesidad de construcciones if-else o cambios de declaraciones como lo demuestra esta publicación en el blog , donde enum.method() hace lo que originalmente se ejecutaría dentro del condicional. El mismo ejemplo también muestra el uso de importaciones estáticas con enums y produce un código tipo DSL mucho más limpio.

Algunas otras cualidades interesantes incluyen el hecho de que las enumeraciones proporcionan implementación para equals() , toString() y hashCode() e implementan Serializable y Comparable .

Para un resumen completo de todas las enumeraciones que tienen que ofrecer, recomiendo encarecidamente la cuarta edición de Thinking in Java, de Bruce Eckel, que dedica un capítulo entero al tema. Particularmente ilustrativos son los ejemplos que involucran un juego de Rock, Papel, Tijeras (es decir, RoShamBo) como enumeraciones.




Enum hereda todos los métodos de la clase Object y la clase abstracta Enum . Así que puedes usar sus métodos de reflexión, multihilo, serilización, comparable, etc. Si declaras una constante estática en lugar de Enum, no puedes. Además de eso, el valor de Enum también se puede pasar a la capa DAO.

Aquí hay un programa de ejemplo para demostrar.

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}



Ahora, ¿por qué y para qué debería usar enum en la programación diaria?

Puede usar un Enum para representar un conjunto fijo pequeño de constantes o un modo de clase interno mientras aumenta la legibilidad. Además, los Enums pueden imponer cierta rigidez cuando se usan en los parámetros del método. Ofrecen la interesante posibilidad de pasar información a un constructor como en el ejemplo de los Planetas en el sitio de Oracle y, como ha descubierto, también permiten una forma simple de crear un patrón singleton.

ej .: Locale.setDefault(Locale.US) lee mejor que Locale.setDefault(1) e impone el uso de un conjunto fijo de valores que se muestra en un IDE cuando agrega el . separador en lugar de todos los enteros.







enum significa enum eración, es decir, mencionar (una cantidad de cosas) una por una.

Una enumeración es un tipo de datos que contiene un conjunto fijo de constantes.

O

Una enum es como una class , con un conjunto fijo de instancias conocido en tiempo de compilación.

Por ejemplo:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

Ventajas de enum:

  • enum mejora la seguridad del tipo en la verificación en tiempo de compilación para evitar errores en el tiempo de ejecución.
  • enum se puede usar fácilmente en el interruptor
  • enum se puede atravesar
  • enum puede tener campos, constructores y métodos
  • enum puede implementar muchas interfaces pero no puede extender ninguna clase porque internamente extiende la clase Enum

para more




Utilizaría las enumeraciones como un útil instrumento de mapeo, evitando múltiples if-else siempre que se implementen algunos métodos.

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

Entonces el método by(String label) permite obtener el valor enumerado por no enumerado. Además, uno puede inventar mapas entre 2 enumeraciones. También podría probar '1 a muchos' o 'muchos a muchos' además de la relación predeterminada 'uno a uno'

Al final, enum es una clase de Java. De modo que puede tener el método main dentro, lo que puede ser útil cuando necesite hacer algunas operaciones de mapeo en args inmediato.




Enum es el reemplazo de la definición tradicional de múltiples variables finales estáticas en Java, y se usa mucho cuando tiene un conjunto fijo de constantes razonables.

Veo que el beneficio más importante de enum es cuando defines un método que acepta un argumento constante. De esta manera, fuerza a los llamadores del método a comprometerse con las constantes predefinidas y evitar que pasen valores aleatorios constantes.

Referencia: Cómo usar Enums en Java




En mi opinión, todas las respuestas que obtuvo hasta ahora son válidas, pero en mi experiencia, lo expresaría en pocas palabras:

Use enumeraciones si desea que el compilador compruebe la validez del valor de un identificador.

De lo contrario, puedes usar cadenas como siempre lo hiciste (probablemente definiste algunas "convenciones" para tu aplicación) y serás muy flexible ... pero no obtendrás el 100% de seguridad contra errores tipográficos en tus cadenas y solo las realizarás en tiempo de ejecución.