javaenums

Enum.values() vs EnumSet.allOf( ). Which one is more preferable?


I looked under the hood for EnumSet.allOf() and it looks very efficient, especially for enums with less than 64 values.

Basically all sets share the single array of all possible enum values and the only other piece of information is a bitmask which in case of allOf() is set in one swoop.

On the other hand Enum.values() seems to be a bit of black magic. Moreover it returns an array, not a collection, so in many cases it must be decorated with Arrays.asList() to be usable in any place that expects a collection.

So, should EnumSet.allOf() be more preferable to Enum.values()?

More specifically, which form of for iterator should be used:

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

or

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

Solution

  • Because I did not receive the answer to my question on which one is more efficient, I've decided to do some testing of my own.

    I've tested iteration over values(), Arrays.asList( values() ) and EnumSet.allOf( ). I've repeated these tests 10,000,000 times for different enum sizes. Here are the test results:

    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
    

    These are results for tests ran from command line. When I ran these tests from Eclipse, I got overwhelming support for testValues. Basically it was smaller than EnumSet even for small enums. I believe that the performance gain comes from optimization of array iterator in for ( val : array ) loop.

    On the other hand, as soon as you need a java.util.Collection to pass around, Arrays.asList( ) looses over to EnumSet.allOf, especially for small enums, which I believe will be a majority in any given codebase.

    So, I would say you should use

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

    but

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

    And only use Arrays.asList( MyEnum.values( ) ) where java.util.List is absolutely required.