Feb 22
Before the site went down, I noticed that “Tricks with Enums” was somewhat popular. Since it had not been recovered from the site’s unexpected downtime, I am asking anyone who might help, specifically if it can be retrieved by browsing via the browser’s cache, to recover that post.
I am still searching for a new host. If you have any information regarding that, please let me know as well.
I am sorry for all these “Non Code” posts, but until I sort out the recovery of the site, I’m really too pissed to do any writing. Thanks for your understanding.
February 23rd, 2006 at 3:25 am
Recovered from my firefox cache:
————————————————————-
Tricks with Enums
Published by Avah February 19th, 2006 in Language, Performance.
We all know how to use enums - Ordinal values and even their textual names are now accessible. Heck, we can even iterate over all of them, eliminating the need of the old-fashioned C++ “START� and “END� values.
Enums are much more though. Java implements enums as full-fledged classes:
They have constructors, they have methods and they have fields.
They are treated specially in switch statements to make them more efficient.
They have special classes that allows enums to be used as bit-flags, and to be used efficiently when mapping values.
Enums as Classes
When you write a new enum, you are actually creating a class containing static instances of itself - The enum values. The class will extend the class Enum (discussed earlier for its weird generification), and every instance will be initialised with a String - the name of the enum value - and an integer - the enum’s ordinal value.
So, for example, the following enum:
enum CipherType {
RSA,
Blowfish;
}
Is in fact the equivilant of:
class CipherType extends Enum {
public static final CipherType RSA = new CipherType(\”RSA\”, 0);
public static final CipherType Blowfish = new CipherType(\”Blowfish\”, 1);
private static final CipherType[] values = new CipherType[] { RSA, Blowfish };
public static CipherType[] values() { return values.clone(); }
public static CipherType valueOf(String name) { return Enum.valueOf(CipherType.class, name); }
private CipherType(String name, int ord) {
super(name, ord);
}
}
Simple, isn’t it? The compiler does all of this for you. It’s just a regular class and instances, in every way. And as such, you can add methods to it, add fields to it, and then - Use them at your code for good measure. You can see how I used enums in my code as factory methods, and it’s not the only example at all. Almost any time you’d want to use a switch statement to perform something with a known set of parameters or determine a specific value, you could replace it with an enum method or field.
EnumSet and EnumMap
There are two classes provided with enums and for enums. The EnumSet class is implemented internally with a bit-vector, so that it’s a true flag. No more “and�s and “or�s - Use it like any other Set and it will do the hard work for you. For example, statements like if ((flag & SomeEnum.SomeValue) == SomeEnum.SomeValue) { .. } are replaced with the much more readable statement if (flag.contains(SomeEnum.SomeValue)) { .. }. Also, calls to methods where flags are required will use EnumSet.of(SomeEnum.SomeValue, SomeEnum.SomeOtherValue) instead of the awkward “or� semantic.
The second provided class is EnumMap and it uses an array and the automatically generated ordinal values of the enum to locate and store values according to these enums. This is a great boost to performance and every time you wish to map anything using an enum as key, you should use this class.
Performancing your switch statements
This is just being nit-picking, but for some it might be important. The switch statement is implemented under the hood in two ways: Either it is using an array as a table to locate the code to jump to according to the given value, or it uses a lookup table where it needs to search through a list of values, which is less efficient than the table. Because of that, the lookup table is used only when an array can’t be used, or in other words: When the values used for the cases are not sequential enough.
All that said, when enums are used in a switch statement, it’s their ordinal value that is being compared. That is, a table is always used for enums. So, if any of the previous paragraphs didn’t convince you to use enums yet, this really should!
Seriously now, I guess that’s what happens when you mess around with bytecode for fun.