viernes, 10 de febrero de 2012

Por qué usar enums en vez de constantes en Java

Java
En las versiones anteriores a la versión 1.5 o 5 de Java no existían los tipos de datos enum con lo que debíamos usar constantes de la siguiente forma:

public static String COLOR_ROJO = "rojo";
public static String COLOR_VERDE = "verde";
public static String COLOR_AZUL = "azul";

A partir de la versión 5 de Java se incorporarón al lenguaje los tipos de datos enumerados con el objetivo de mejorar varios aspectos sobre el uso de las constantes. Básicamente, un enum en Java es un conjunto fijo y relacionado de constantes como pueden ser los días de la semana y deberían usarse siempre que se necesite representar un conjunto de constantes con esas características. La característica de relacionado es importante, las constantes solo lo están por la convención que sigamos al darles un nombre. Los enums se definen de la siguiente forma:

public enum Dia {
 LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO
}

public enum Color {
        ROJO("FF0000"), 
 VERDE("00FF00"), 
 AZUL("0000FF");

 private final String rgb;

 Color(String rgb) {
  this.rgb = rgb;
 }

 public String getRGB() {
  return rgb;
 }
}

Como son constantes por las convenciones del lenguaje se escriben en mayúscula. Pero los enum son algo más que constantes, la clase del tipo del enum puede definir métodos y otras propiedades, como el método getRGB del ejemplo anterior o en el siguiente caso que se usa el método values() y que se añade automáticamente a todos los enums.

for (Dia d : Dia.values()) {
    System.out.printf("El día de la semana %s", d);
}

for (Color c : Color.values()) {
    System.out.printf("El color %s tiene como RGB %s", c, c.getRGB());
}

Algunas cosas que hacen de los enum muy interesantes es que al definir las constantes de este modo obtenemos «type safety». Si decimos que un método de una clase recibe un enum el compilador comprobará en tiempo de compilación que cuando lo usamos le pasemos realmente un valor de ese enum, cosa que con constantes definidas como int o String el compilador solo comprueba que pasemos un int o String y por tanto podremos pasar cualquier valor aunque no sea una de las constantes esperadas por el método. Otra de las ventajas que ya se ve en ejemplo anterior es que los enums pueden tener comportamiento a través de los métodos que defina. También, específicamente diseñadas para los enums existen las clases EnumSet y EnumMap que trabajan con enums de forma más eficiente que con Set y Map. Además, los enums pueden ser usados en expresiones switch cosa que con constantes de tipo String solo podemos hacer a partir de la versión 7 de Java..

Para comprarar valores de enums podemos hacerlo con el operador == o con el método equals. Usar el operador == tiene la ventaja de evitar un posible NullPointerException y de que el compilador comprueba que se estén comparando dos valores del mismo enum.

== nunca lanza NullPointerException

Dia dia = null;
if (dia == Dia.LUNES);      // se ejecuta
if (dia.equals(Dia.LUNES)); // lanza NullPointerException

== comprueba compatibilidad de tipos en tiempo de compilación

if (Dia.LUNES.equals(COLOR.ROJO)); // compila bien
if (DIA.LUNES == COLOR.ROJO);      // no compila, incompatibilidad de tipos

Estos son motivos suficientes para usar enums en vez de constantes y == en vez de equals para los enums a partir de la versión 5 de Java. Las constantes son mejor que tener en nuestro código «hardcodeados» los valores y con ellas obtendremos la asistencia de IDEs como eclipse para saber donde se utilizan y podremos hacer un refactor si necesitamos hacer un cambio de nombres («refactorización»). Pero los enums superan en ventajas a las constantes por los motivos anteriores asi que si podemos utilizar en nuestros proyectos Java 5 o superior es aconsejable utilizarlos.

Referencia:
http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
http://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals
http://www.javabeat.net/tips/171-how-to-use-enum-in-switch.html