values enum java enums

values - foreach enum java



Enum.values() vs EnumSet.allOf(). ¿Cuál es más preferible? (6)

Busqué EnumSet.allOf y parece muy eficiente, especialmente para enumeraciones con menos de 64 valores.

Básicamente, todos los conjuntos comparten la única matriz de todos los valores de enum posibles y la única otra información es una máscara de bits que en el caso de allOf se configura de una sola vez.

Por otro lado, Enum.values ​​() parece ser un poco de magia negra. Además, devuelve una matriz, no una colección, por lo que en muchos casos debe decorarse con Arrays.asList () para que se pueda utilizar en cualquier lugar que espere la recopilación.

Entonces, ¿debería EnumSet.allOf ser más preferible a Enum.values ?

Más específicamente, qué forma de for iterator debería usarse:

for ( final MyEnum val: MyEnum.values( ) );

o

for ( final MyEnum val: EnumSet.allOf( MyEnum.class ) );


Debe usar el enfoque más simple y claro para usted. El rendimiento no debe ser una consideración en la mayoría de las situaciones.

En mi humilde opinión: ninguna opción funciona muy bien, ya que ambos crean objetos. Uno en el primer caso y tres en el segundo. Podría construir una constante que contenga todos los valores por razones de rendimiento.


Debido a que no recibí la respuesta a mi pregunta sobre cuál es más eficiente, he decidido hacer algunas pruebas por mi cuenta.

He probado la iteración sobre los values() , Arrays.asList( values() ) y EnumSet.allOf( ) . He repetido estas pruebas 10,000,000 veces para diferentes tamaños de enum. Aquí están los resultados de la prueba:

oneValueEnum_testValues 1.328 oneValueEnum_testList 1.687 oneValueEnum_testEnumSet 0.578 TwoValuesEnum_testValues 1.360 TwoValuesEnum_testList 1.906 TwoValuesEnum_testEnumSet 0.797 ThreeValuesEnum_testValues 1.343 ThreeValuesEnum_testList 2.141 ThreeValuesEnum_testEnumSet 1.000 FourValuesEnum_testValues 1.375 FourValuesEnum_testList 2.359 FourValuesEnum_testEnumSet 1.219 TenValuesEnum_testValues 1.453 TenValuesEnum_testList 3.531 TenValuesEnum_testEnumSet 2.485 TwentyValuesEnum_testValues 1.656 TwentyValuesEnum_testList 5.578 TwentyValuesEnum_testEnumSet 4.750 FortyValuesEnum_testValues 2.016 FortyValuesEnum_testList 9.703 FortyValuesEnum_testEnumSet 9.266

Estos son los resultados de las pruebas ejecutadas desde la línea de comandos. Cuando realicé estas pruebas desde Eclipse, obtuve un apoyo abrumador para testValues . Básicamente, era más pequeño que EnumSet incluso para enums pequeños. Creo que la ganancia de rendimiento proviene de la optimización del iterador de matriz en el ciclo for ( val : array ) .

Por otro lado, tan pronto como necesite pasar java.util.Collection, Arrays.asList( ) pierde en EnumSet.allOf , especialmente para las enumeraciones pequeñas, que creo que serán la mayoría en cualquier código base.

Entonces, yo diría que deberías usar

for ( final MyEnum val: MyEnum.values( ) )

pero

Iterables.filter( EnumSet.allOf( MyEnum.class ), new Predicate< MyEnum >( ) {...} )

Y solo use Arrays.asList( MyEnum.values( ) ) donde java.util.List es absolutamente necesario.


El método de values() es más claro y eficiente si solo desea iterar sobre todos los valores enum posibles. Los valores son almacenados en caché por la clase (ver Class.getEnumConstants() )

Si necesita un subconjunto de valores, debe usar un EnumSet . Comience con allOf() o noneOf() y agregue o elimine valores o use solo of() como lo necesite.


No es que haya pasado por toda la implementación, pero me parece que EnumSet.allOf () básicamente está usando la misma infraestructura que .values ​​(). Por lo tanto, esperaría que EnumSet.allOf () requiera algunos pasos adicionales (probablemente insignificantes) (consulte http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988 ).

Me parece claro que el uso previsto de foreach es for(MyEnum val : MyEnum.values()) ¿por qué hacerlo de manera diferente? Solo confundirá al programador de mantenimiento.

Quiero decir, si necesitas una colección, deberías obtener una. Si desea utilizar un foreach, las matrices son lo suficientemente buenas. ¡Prefiero las matrices si me presionan! ¿Por qué envolver algo con algo, si lo que tienes (matriz) es lo suficientemente bueno? Las cosas simples son normalmente más rápidas.

De todos modos, Peter Lawrey tiene razón. No se preocupe por el rendimiento de esto ... Es lo suficientemente rápido, y es probable que haya millones de otros cuellos de botella que hacen que esa pequeña diferencia de rendimiento teórico sea totalmente irrelevante (sin embargo, no veo su punto de "creación de objetos"). el ejemplo parece estar 100% bien).


También hay Class.getEnumConstants()

bajo el capó todos llaman métodos values() de tipos enum de todos modos, a través de la reflexión .


EnumSet no está construido con la intención de iterar sobre sus valores. Más bien se implementa con la idea de que represente un BitMap o BitMask de manera eficiente (o razonablemente eficiente). El javadoc en EnumSet también declara:

Los conjuntos Enum están representados internamente como vectores de bits. Esta representación es extremadamente compacta y eficiente. El rendimiento de espacio y tiempo de esta clase debería ser lo suficientemente bueno como para permitir su uso como una alternativa de alta calidad y segura para tipos de "indicadores de bits" tradicionales basados ​​en int. Incluso las operaciones masivas (como containsAll y retainAll) deberían ejecutarse muy rápidamente si su argumento también es un conjunto de enumeración.

Como solo un bit único puede representar un cierto valor de Enum, también se implementa como un Set y no como una List .

Ahora, probablemente también sea cierto que puede lograr lo mismo, y más rápido, usando máscaras de bits estilo C (x ^ 2), sin embargo, ofrece un estilo de codificación más intuitivo y escribe un uso seguro usando enumeraciones, y se expande fácilmente más allá del tamaño de lo que puede contener un int o un long

Como tal, puede probar que todos los bits se establecen de la siguiente manera:

public class App { enum T {A,B} public static void main(String [] args) { EnumSet<T> t = EnumSet.of(T.A); t.containsAll(EnumSet.allOf(T.class)); } }