Enum.values ​​() vs EnumSet.allOf (). Lequel est plus préférable?

J’ai regardé sous le capot pour EnumSet.allOf et il semble très efficace, en particulier pour les énumérations avec moins de 64 valeurs.

Fondamentalement, tous les ensembles partagent le seul tableau de toutes les valeurs d’énumération possibles et le seul autre élément d’information est un masque de bits qui, dans le cas de allOf est défini sur un seul allOf .

Par contre, Enum.values ​​() semble être un peu de magie noire. De plus, il retourne un tableau, pas une collection, donc dans de nombreux cas, il doit être décoré avec Arrays.asList () pour pouvoir être utilisé dans n’importe quel endroit qui attend la collecte.

Donc, EnumSet.allOf devrait- EnumSet.allOf être préférable à Enum.values ?

Plus précisément, quelle forme de for iterator doit être utilisée:

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

ou

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

Parce que je n’ai pas reçu la réponse à ma question sur laquelle est le plus efficace, j’ai décidé de faire mes propres tests.

J’ai testé l’itération sur les values() , Arrays.asList( values() ) et EnumSet.allOf( ) . J’ai répété ces tests 10 000 000 fois pour différentes tailles de enum. Voici les résultats du test:

 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 

Ce sont des résultats pour les tests exécutés à partir de la ligne de commande. Lorsque j’ai effectué ces tests à partir d’Eclipse, j’ai obtenu un soutien écrasant pour testValues . Fondamentalement, il était plus petit que EnumSet même pour les petites énumérations. Je pense que le gain de performance provient de l’optimisation de l’iterator de tableau dans la boucle for ( val : array ) .

D’un autre côté, dès que vous avez besoin d’un java.util.Collection pour circuler, Arrays.asList( ) perd le contrôle sur EnumSet.allOf , en particulier pour les petites énumérations, qui, je pense, seront majoritaires dans une base de code donnée.

Donc, je dirais que vous devriez utiliser

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

mais

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

Et n’utilisez que Arrays.asList( MyEnum.values( ) )java.util.List est absolument requirejs.

Vous devez utiliser l’approche la plus simple et la plus claire pour vous. La performance ne devrait pas être prise en compte dans la plupart des situations.

IMHO: aucune des deux options ne fonctionne très bien car elles créent des objects. Un dans le premier cas et trois dans le second. Vous pouvez construire une constante contenant toutes les valeurs pour des raisons de performances.

Il y a aussi Class.getEnumConstants()

sous le capot, ils appellent tous des méthodes de type enum de values() , par reflection .

La méthode values() est plus claire et performante si vous voulez simplement parcourir toutes les valeurs d’énumération possibles. Les valeurs sont mises en cache par la classe (voir Class.getEnumConstants() )

Si vous avez besoin d’un sous-ensemble de valeurs, vous devez utiliser un EnumSet . Commencez avec allOf() ou noneOf() et ajoutez ou supprimez des valeurs ou utilisez simplement of() selon vos besoins.

Non pas que je suis passé par toute l’implémentation, mais il me semble que EnumSet.allOf () utilise essentiellement la même infrastructure que .values ​​(). Je pense donc que EnumSet.allOf () nécessite des étapes supplémentaires (probablement négligeables) (voir http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988 ).

Il me semble clair que l’utilisation prévue de foreach est for(MyEnum val : MyEnum.values()) pourquoi le faire différemment? Vous ne ferez que confondre le programmeur de maintenance.

Je veux dire, si vous avez besoin d’une collection, vous devriez en avoir une. Si vous voulez utiliser un foreach, les tableaux sont assez bons. Je préfère même les tableaux si pressés! Pourquoi emballer quelque chose avec quoi que ce soit, si ce que vous avez (array) est assez bon? Les choses simples sont normalement plus rapides.

En tout cas, Peter Lawrey a raison. Ne vous préoccupez pas des performances de ce disque. C’est assez rapide, et il y a des millions d’autres goulots d’étranglement qui rendent cette infime différence de performance théorique totalement inutile (ne voyez pas son sharepoint “création d’object”. exemple semble être 100% OK).

EnumSet n’est pas conçu avec l’intention de parcourir ses valeurs. Il est plutôt implémenté avec l’idée de représenter un BitMap ou un BitMask efficacement (ou raisonnablement efficace). Le javadoc sur EnumSet indique également:

Les ensembles enum sont représentés en interne en tant que vecteurs de bits. Cette représentation est extrêmement compacte et efficace. Les performances spatiales et temporelles de cette classe devraient être suffisantes pour permettre son utilisation en tant qu’alternative de haute qualité et sûre aux “indicateurs de bits” traditionnels basés sur l’intelligence. Même les opérations en masse (telles que containsAll et retainAll) doivent s’exécuter très rapidement si leur argument est également un enum.

Un seul bit pouvant représenter une certaine valeur Enum, il est également implémenté en tant Set et non en tant que List .

Maintenant, il est probablement également possible d’utiliser les masques de bits de style C (x ^ 2), plus rapidement et de la même manière, mais il offre un style de codage plus intuitif et une utilisation sûre des types enums. taille de ce qu’un int ou long peut contenir.

En tant que tel, vous pouvez tester que tous les bits sont définis comme suit:

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