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

JavaEnums

Java Problem Overview


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 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 ) );

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

There is also Class.getEnumConstants()

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

Solution 4 - Java

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.

Solution 5 - Java

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).

Solution 6 - Java

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));
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexander PogrebnyakView Question on Stackoverflow
Solution 1 - JavaAlexander PogrebnyakView Answer on Stackoverflow
Solution 2 - JavaPeter LawreyView Answer on Stackoverflow
Solution 3 - JavairreputableView Answer on Stackoverflow
Solution 4 - JavaArne BurmeisterView Answer on Stackoverflow
Solution 5 - JavaEnno ShiojiView Answer on Stackoverflow
Solution 6 - JavaYoYoView Answer on Stackoverflow