There is more to an EnumSet than an int, such as the Set interface. What may be the case is after inlining that the relevant membership tests become int operations. but HotSpot doesn’t do anything without it being bytecode first. JIT does a lot, but it’s not magic
No, it’s directed at people who are actually fretting about Enums having more overhead than ints.
For the sake of it, I benchmarked java.util.RegularEnumSet, and unfortunately even in 6u26 it suffers from the interface overhead.
static enum Test
{
A, B, C, D, E, F, G, H, I, J, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z;
}
private static void benchmark(Set<Test> tests, Test value)
{
for (int i = 0; i < 16 * 1024 * 1024; i++)
{
tests.contains(value);
}
}
Set<Test> enumSet = EnumSet.of(Test.A, Test.B);
Set<Test> hashSet = new HashSet<Test>();
Set<Test> treeSet = new TreeSet<Test>();
for (Test test : enumSet)
{
hashSet.add(test);
treeSet.add(test);
}
{
long t0 = System.nanoTime();
benchmark(enumSet, Test.A);
long t1 = System.nanoTime();
System.out.println("enum took: " + (t1 - t0) / 1000000 + "ms");
}
{
long t0 = System.nanoTime();
benchmark(hashSet, Test.A);
long t1 = System.nanoTime();
System.out.println("hash took: " + (t1 - t0) / 1000000 + "ms");
}
{
long t0 = System.nanoTime();
benchmark(treeSet, Test.A);
long t1 = System.nanoTime();
System.out.println("tree took: " + (t1 - t0) / 1000000 + "ms");
}
If you change the order of execution of the different types of Set you can see massive performance differences.
Results for Server VM 6u26:
enum took: 7ms <-- first
hash took: 125ms
tree took: 133ms
hash took: 150ms
tree took: 104ms
enum took: 130ms <-- last
Just so you know. And yes, and instance is allocated.
The main issue I have is that if you want to use enums heavily, then it requires lots of enum declarations. That is a scenario where symbols/atoms work much better, because you are essentially declaring the enums within their usage, making the code much more terse.
You could then also add guards or pattern matching, for automatic verifying parameters. These would then be verified using type inference, or at runtime. But I don’t think Java could really take guards and symbols, or should really get them. Both would be moving away from Java’s static type system, which wouldn’t fit the philosophy of the language.
So I think Java enums work well for Java, but aren’t so great when compared to what you can do in other languages.
Why assign them to Set rather than their concrete types if you want to test their comparative speed?
EnumSets are the one time I don’t use the general convention of using the interface for fields and method parameters anyway - using EnumSet seems somehow more semantically correct to me.
Don’t forget that EnumSets are mutable, so you can get away with allocating once in a lot of cases if you feel the need (I don’t, but then I’m not targeting Android! )
I remember working on reverse engineering the communications of a game. Some objects in the game allowed the user to interact with them and a random numbr was generated. When we started digging into to communications we found that the number was being generated client side then was sent to the server so all of the clients would see the result. In this situation they were not using enums and an invalid number did one of two things, A) if set to 0 the animation for that item kept going. B) if set to more then 8 or less then 0 the item would crash all clients viewing that item.
All in all it was very entertaining to watch the problems produced by poor coding (no data verification nor range checking of the client)
I’m just saying, Java enums take so long to write I might as well just make a class. I just want MyEnum = enum { A, B, C, D} and then I can just say MyEnum.A whenever. It’s good to know that Java enums become ints under the hood, but for me enums are completely convenience anyway - when I can just use an int or a string I type all over my code if I want. Something that’s supposed to be convenient shouldn’t be so inconvenient.
I’m a huge fan of enums and particularly extensible enums. One of the problems of extensible enums is that you can’t use them in EnumSet. EnumSet is necessary to perform set operations efficiently otherwise things get particularly horrendous especially on Android. I created a new collection ExtEnumSet that is like EnumSet, but supports extensible enums. I wrote more here:
I’ve moved to the ExtEnumSet for storing entity state in my ES.
Another problem with EnumSet is that under the hood it keeps track of a unique array of Enums for the given supported type for each EnumSet. Ahh… This may be the case for Java 5, but I just checked in Java 6 source and it looks like this array is universally shared which wasn’t the case in Java 5 if I recall correctly. I actually finally had to move to Java 6 due to javac / compiler issues with some sort of generic method failure with Java 5.
Anyway… I’m a huge fan of extensible enums and they were the final missing key to really unlock state tracking between unrelated components in the component architecture I’m releasing soon; useful in so many ways. Also it’s quite easy to use enums extensible or not as components in my component architecture. I yap on a bit about that in the long ES topic on B^3’s blog: http://t-machine.org/index.php/2011/08/22/entity-system-rdbms-beta-a-new-example-with-source/comment-page-1/#comment-30180
[edit] hah, that link to the ES comment is silly Adam / B^3 ruffled my feathers slightly, so I kind of go a little off in that reply… It’s the one where I described using enums as components though. :o The whole thread is a fairly spirited discussion of sorts…