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

后端 未结 6 1153
滥情空心
滥情空心 2020-12-23 09:05

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 singl

相关标签:
6条回答
  • 2020-12-23 09:40

    You should use the approach which is simplest and clearest to you. Performance shouldn't be a consideration in most situations.

    IMHO: neither option performs very well as they both create objects. One in the first case and three in the second. You could construct a constant which holds all the values for performance reasons.

    0 讨论(0)
  • 2020-12-23 09:54

    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.

    0 讨论(0)
  • 2020-12-23 09:59

    Not that I went through the entire implementation, but it seems to me that EnumSet.allOf() is basically using the same infrastructure as .values(). So I'd expect EnumSet.allOf() requires some (probably negligible) additional steps (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6276988).

    It seems clear to me that the intended use of foreach is for(MyEnum val : MyEnum.values()) why do it differently? You will only confuse the maintenance programmer.

    I mean, if you need a collection, you should get one. If you want to use a foreach, arrays are good enough. I'd even prefer arrays if pressed! Why wrap anything with anything, if what you got (array) is good enough? Simple things are normally faster.

    In anyways, Peter Lawrey is right. Don't bother about the performance of this.. It's fast enough, and chances are there are million other bottlenecks that render that tiny theoretical performance difference as totally irrelevant (Don't see his "object creation" point though. To me the first example seems to be 100% OK).

    0 讨论(0)
  • 2020-12-23 10:00

    The values() method is more clear and performant if you just want to iterate over all possible enum values. The values are cached by the class (see Class.getEnumConstants())

    If you need a subset of values, you should use an EnumSet. Start with allOf() or noneOf() and add or remove values or use just of() as you need.

    0 讨论(0)
  • 2020-12-23 10:02

    There is also Class.getEnumConstants()

    under the hood they all call values() methods of enum types anyway, through reflection.

    0 讨论(0)
  • 2020-12-23 10:02

    EnumSet is not built with the intention to iterate over it's values. Rather it is implemented with the idea for it to represent a BitMap or BitMask efficiently (or reasonably efficient). The javadoc on EnumSet also states:

    Enum sets are represented internally as bit vectors. This representation is extremely compact and efficient. The space and time performance of this class should be good enough to allow its use as a high-quality, typesafe alternative to traditional int-based "bit flags." Even bulk operations (such as containsAll and retainAll) should run very quickly if their argument is also an enum set.

    Because only one single bit can represent a certain Enum value, it is also implemented as a Set and not as a List.

    Now, it is probably also true that you can accomplish the same, and faster, using C-style bit masks (x^2), however it offers a more intuitive coding style and type safe use using enums, and it expands easily beyond the size of what an int or long can contain.

    As such you can test that all bits are set as follows:

    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));
      }
    }
    
    0 讨论(0)
提交回复
热议问题