• Home
  • About
  • Beautiful Java Enums

    File under “It’s never too late to blog about Java 5 features” and “you wrote 1000 words on what?”.

    Way back before Java 5 I fell in love with the Type Safe Enum pattern described in Martin Fowler’s Refactoring. You know the one, where an instance of a class has members of itself as public static fields. It was so clever (not always a compliment) and I applied it everywhere I could. Fowler’s example dealt with blood types:

    
    public class BloodType {
       public static final BloodType TYPE_A = new BloodType();
       public static final BloodType TYPE_B = new BloodType();
    
       private BloodType() {}
    }
    

    For the most part you had a finite amount of BloodTypes in your system and you could use == for comparisons, which was sort of guaranteed by the private constructor. Kinda sorta in that serialization, class loader, or reflection shenanigans could break this. But safe enough anyway. It was such a good idea that Java 5 created a new keyword called “enum” and built the pattern into the language. Java developers reveled in the newfound productivity of having to produce about 130 less bytes of source code.
    
    public enum BloodType {
       TYPE_A,
       TYPE_B;
    }
    

    Java enum types came with some guarantees about equality and instances but honestly I can’t remember the specifics and am too lazy to go look them up. This new way was seen as a big improvement because the idea a “complexity budget” hadn’t been invented yet and there were no vocal bloggers clamoring for a simpler, more consistent Java. I wonder today if we really needed this new introduction to the type system, but that is a post for another day. I liked enums and still do. They were meant to replace integer based abominations like this, which would make an API horrible to work with (I’m looking at you Swing):
    
    public class BloodType {
       public static final int TYPE_A = 0;
       public static final int TYPE_B = 1;
    }
    

    And don’t even get me started about bitmasking these damn values. Ugh, horror. Few developers knew about the Type Safe Enum Pattern, so it was the right call to back it into the language and move people away from integer based APIs.

    Back to Java 5 enums. There are a few API methods around the Enum type which you should not use. First is ordinal() which gives you the integer based position in which your enum instance was declared. TYPE_A is 0 and TYPE_B is 1. The Javadoc gives a nice little warning: “Most programmers will have no use for this method.” But apparently enough people did use it that Joshua Bloch’s Effective Java 2nd Edition felt the need to expand this sentence to about 3 pages. This integer is subject to change without warning! My current IDE setup autoformats code and alphabetizes these darn things. Writing code that depends on the order of the enum declaration is bad. Don’t do it unless you are writing something like EnumSet or EnumMap.

    Another method to not use is name(), which gives you the type name, like “TYPE_A” or “TYPE_B” (which incidentally is the same thing toString() gives you). This is handy but the Javadoc gives a not-very-specific warning: “Most programmers should use the toString() method in preference to this one, as the toString method may return a more user-friendly name.” If you use name() then you are dependent on the actual declaration name of the enum entry. Future refactoring may break your system and you’ll be stuck not able to change enum names if you want to. Instead rely on toString if you really need to. That way your implementation (the name of your enum) and the public API can change independently of one another. Sure, you may never need it, but it takes very little effort to use toString instead, so just do it.

    Of course, your system shouldn’t rely on toString() either, unless you are rendering the enum into a log file or user interface. Instead, I like to add a String name to all of my enums:

    
    public enum BloodType {
     TYPE_A("A"), TYPE_B("B");
    
     private final String name;
    
     private BloodType(String name) {
       this.name = name;
     }
    
     public String getName() {
       return name;
     }
    }
    

    Again, this is a small change that gives you future flexibility. If the String description or name of your enum is important than model it. Yeah, you might not need it, and Java makes it kinda verbose, but a dependency on toString() is both a bad idea and a simple thing to get rid of, so just do it.

    The bigger problem with name() is that it is often used in conjunction with valueOf(Class, String) which allows you to lookup an Enum entry based on the string representation. I see this often in generated code, in particular around the JDK wsimport tool to create objects from a WSDL. If you have code like this, using the native enum name(), valueOf(), and XML schema definitions for enumerated values, then you will always have to change all three definitions at once: The web service .xsd, the clients, and the generated code. Having a single change affect multiple source files is an antipattern called “Shotgun Surgery“. Hopefully you have control over all your clients, but if you have a public web service then you’re going to be stuck with your names for quite a while. A simple way to make your enums flexible and future-proof is to keep your own map of Strings to enum instances and provide a translation method instead of relying on valueOf:

    
    public enum BloodType {
     TYPE_A("A"), TYPE_B("B"), TYPE_O("O");
    
     private final String name;
    
     private static final Map<String, BloodType> map = 
                                 new HashMap<String, BloodType>();
    
     static {
       for (BloodType type : BloodType.values()) {
         map.put(type.name, type);
       }
     }
    
     private BloodType(String name) {
       this.name = name;
     }
    
     public String getName() {
       return name;
     }
    
     public static BloodType fromString(String name) {
       if (map.containsKey(name)) {
         return map.get(name);
       }
       throw new NoSuchElementException(name + "not found");
     }
    }
    

    The static block just stuffs all the enum values into a lookup map based on their name. Then a fromString(String) method can be written that hands you back an enum instance for a String. You have flexibility on whether to return null or throw an exception when the String is unrecognized.

    The value here is complete control over the names of elements. Say you want to recognize “A_POSITIVE” and “A_NEGATIVE” as TYPE_A… well now you can. Or perhaps you want it case insensitive… just change the implementation. The Enum.valueOf method is static, and as far as I know there is not way to change it! About the only thing you can override in Enum is toString(). This whole thing is a pretty easy pattern to write and it buys you quite a bit of future flexibility, so just do it.

    Is this a little verbose? Sure. Are you sure you need this future flexibility? Not completely. Will you be screwed later if you don’t write enums this way? Quite possibly. Is it worthwhile? I think so, and hopefully I’ve convinced you as well.

    Got Java problems? Canoo can help. Email info@canoo.com to learn more about what we can do for your project. You’ll be glad you did.

    Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
    • Y!GG
    • Webnews
    • Digg
    • del.icio.us
    • DotNetKicks
    • Facebook
    • Google Bookmarks
    • Newsrider
    • Newstube
    • TwitThis
    • YahooBuzz

    5 Comments

    1. Dimitris said,

      September 25, 2010 @ 8:08 am

      I have come to the exact same conclusions. However, even the final version is not refactor-safe, e.g. try to persist it with JPA. Also looks like a monster taking into account that in most cases enums are inner classes.

    2. Reinier Zwitserloot said,

      September 25, 2010 @ 10:30 pm

      Don’t reorder enums. switch ( someEnum ) uses .ordinal() implicitly, so if you reorder an enum, or your IDE reorders it for you, any code that’s already out there relying on your classes will silently break (as in, run the wrong case block).

      What IDE, incidentally, alphabetizes your enum? You might want to get rid of it.

    3. Dan Howard said,

      September 26, 2010 @ 11:00 am

      Good post. The only thing I would add is that I would make fromString not throw an exception and instead return null. Throwing an exception is what\\\’s annoying about the valueOf method. In 99% of cases you don\\\’t want the exception. Why bother putting try-catch around every call to this when usually this would be part of a simple switch? Additionally what I like to have is a case-insensitive search in fromString.

    4. Hamlet said,

      September 26, 2010 @ 7:49 pm

      I use a “Rearranger” plugin that forces code into my company’s standard guidelines. Wow, I never thought about it but putting an enum in a switch statement is just bad. That is horribly unexpected.

    5. Vineet Manohar said,

      September 27, 2010 @ 4:12 pm

      I agree. Developers should especially not rely on ordinal values or enum names when they are trying to serialize enum values to a file system or database. Have a business value associated with the enum and serialize that instead. For more on enum serialization, see my blog post http://www.vineetmanohar.com/2010/01/3-ways-to-serialize-java-enums/ It also shows you how to return null instead of throwing an exception when looking up an enum from the serialized value.

    RSS feed for comments on this post