Java: Enum vs. Int

Cuando uso banderas en Java, he visto dos enfoques principales. Uno usa valores int y una línea de sentencias if-else. La otra es usar enumeraciones y declaraciones de cambio de caso.

Me preguntaba si había una diferencia en términos de uso de memoria y velocidad entre el uso de enums vs ints para flags.

Tanto las enums como las enums pueden usar tanto el interruptor como el if-then-else, y el uso de memoria también es mínimo para ambos, y la velocidad es similar; no hay una diferencia significativa entre ellos en los puntos que ha planteado.

Sin embargo, la diferencia más importante es la comprobación de tipos. Enums se verifican, los Enums no.

Considera este código:

 public class SomeClass { public static int RED = 1; public static int BLUE = 2; public static int YELLOW = 3; public static int GREEN = 3; // sic private int color; public void setColor(int color) { this.color = color; } } 

Si bien muchos clientes utilizarán esto correctamente,

 new SomeClass().setColor(SomeClass.RED); 

No hay nada que les impida escribir esto:

 new SomeClass().setColor(999); 

Hay tres problemas principales con el uso del patrón public static final :

  • El problema ocurre en tiempo de ejecución , no en tiempo de comstackción , por lo que será más costoso de arreglar, y más difícil de encontrar la causa
  • else throw new IllegalArgumentException("Unknown color " + color); escribir código para manejar entradas incorrectas, generalmente un if-then-else con un else throw new IllegalArgumentException("Unknown color " + color); final else throw new IllegalArgumentException("Unknown color " + color); – De nuevo caro
  • No hay nada que evite una colisión de constantes: el código de clase anterior se comstackrá aunque YELLOW y GREEN tengan el mismo valor 3

Si usa enums , soluciona todos estos problemas:

  • Su código no se comstackrá a menos que pase valores válidos en
  • No es necesario ningún código especial de “entrada incorrecta”: el comstackdor lo maneja por usted
  • Los valores de Enum son únicos

Incluso puede usar Enums para reemplazar esos indicadores combinados bit a bit como int flags = FLAG_1 | FLAG_2; int flags = FLAG_1 | FLAG_2;

En su lugar, puede usar un tipo de EnumSet seguro :

 Set flags = EnumSet.of(FlagEnum.FLAG_1, FlagEnum.FLAG_2); // then simply test with contains() if(flags.contains(FlagEnum.FLAG_1)) ... 

La documentación indica que esas clases están optimizadas internamente como vectores de bits y que la implementación debería funcionar lo suficientemente bien como para reemplazar las banderas basadas en int.

El uso de memoria y la velocidad no son las consideraciones que importan. No podrías medir una diferencia de ninguna manera.

Creo que las enums deberían preferirse cuando se aplican, porque enfatizan el hecho de que los valores elegidos van juntos y comprenden un conjunto cerrado. La legibilidad también se mejora mucho. El código que utiliza enums es más autodocumentado que los valores de int extraviados dispersos por todo el código.

Prefiero enums.

Una de las razones por las que verá algún código utilizando int flags en lugar de una enum es que Java no tenía enumeraciones hasta que Java 1.5

Entonces, si está buscando un código que fue originalmente escrito para una versión anterior de Java, entonces el patrón int era la única opción disponible.

Hay un número muy pequeño de lugares donde el uso de int flags es aún preferible en el código Java moderno, pero en la mayoría de los casos, debería preferir usar una enum , debido al tipo de seguridad y expresividad que ofrecen.

En términos de eficiencia, dependerá exactamente de cómo se usen. La JVM maneja ambos tipos de manera muy eficiente, pero el método int probablemente sea un poco más eficiente para algunos casos de uso (porque se manejan como primitivos en lugar de objetos), pero en otros casos, la enumeración sería más eficiente (porque no lo hace) Necesito tirar el boxeo / unboxing).

Sería difícil encontrar una situación en la que la diferencia de eficiencia se notara de alguna manera en una aplicación del mundo real , por lo que debe tomar una decisión basada en la calidad del código (legibilidad y seguridad), lo que debería llevarlo a usa una enumeración el 99% del tiempo .

Tenga en cuenta que las enums son enums tipos, y no puede mezclar valores de una enumeración con otra. Esa es una buena razón para preferir los enums sobre los ints para las banderas.

Por otro lado, si usa ints para sus constantes, puede mezclar valores de constantes no relacionadas, como esta:

 public static final int SUNDAY = 1; public static final int JANUARY = 1; ... // even though this works, it's a mistake: int firstMonth = SUNDAY; 

El uso de memoria de enums over enums es insignificante, y las enums seguridad de tipo proporcionan una sobrecarga mínima aceptable.

Responda a su pregunta: No, después de un tiempo insignificante para cargar la clase Enum, el rendimiento es el mismo.

Como otros han declarado, ambos tipos pueden usarse en declaraciones switch o if else. Además, como han indicado otros, debe favorecer los Enume sobre los int flags, ya que fueron diseñados para reemplazar ese patrón y brindan mayor seguridad.

SIN EMBARGO, hay un patrón mejor que usted considera. Proporcionando cualquier valor que se suponía que tu sentencia switch / if debía producir como propiedad.

Mire este enlace: http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html Observe el patrón proporcionado para dar a los planetas masas y radios. Proporcionar la propiedad de esta manera asegura que no se olvide de cubrir un caso si agrega una enumeración.