Discussion & Examples: Java enums versus public static final

By Angsuman Chakraborty, Gaea News Network
Tuesday, September 23, 2008

Should we use to represent a constant String such as browser’s user agent or simply use public static final String as before?
Using public static final as enum has many problems, such as:

  • Not typesafe - Since a type is just an int you can pass in any other int value where a particular type is required, or add two types together (which makes no sense). This is particularly noticeable in C programs where you will find strange constants being used in un-related place and yet it seems to work, simply because the required constant and the provided constant share the same int value.
  • No namespace - You must prefix constants of an int enum with a string  to avoid collisions with other int enum types.
  • Brittleness - Because such enums are compile-time constants, they are compiled into clients that use them. If a new constant is added between two existing constants or the order is changed, clients must be recompiled. If they are not, they will still run, but their behavior will be undefined.
  • Printed values may be uninformative - With int as enum (as in public static final int), if you print one out all you get is a number, which tells you nothing about what it represents, or even what type it is. In Java enums you get full type information along with value.

It is possible to get around these problems by using the Typesafe Enum pattern (explained below), but this pattern has its own problems: It is quite verbose, hence error prone, and its enum constants cannot be used in switch statements.

This is an example of typesafe enum pattern, using a class to represent constants:

//The typesafe enum pattern
public class Suit {
    private final String name;
    public static final Suit CLUBS = new Suit("clubs");
    public static final Suit DIAMONDS = new Suit("diamonds");
    public static final Suit HEARTS = new Suit("hearts");
    public static final Suit SPADES = new Suit("spades");    

    private Suit(String name){
        this.name =name;
    }
    public String toString(){
        return name;
    }
}

The same example with enums would be:

public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

That is simple isn’t it?

To represent Strings as enum, I am using:

public enum UserAgent {
        IE ("IE User Agent"),
        FIREFOX ("Firefox User Agent");

        private final String userAgent;
        private UserAgent(String userAgent) {
            this.userAgent = userAgent;
        }
        public String toString() {
            return userAgent;
        }
    }

This is definitely not simpler than:

public static final String IE = "IE User Agent";
public static final String FIREFOX = "Firefox User Agent";

However with Java enums I get type safety (people cannot pass some junk when I am expecting a known User Agent) and informative types. Do you see any other benefits or a simpler way to accomplish the same?

Discussion
September 24, 2008: 12:37 pm

You are right, thanks.


Ben
September 24, 2008: 8:55 am

With enums you can iterate over UserAgent.values(), use them in a switch/case, and add UserAgent-specific methods in the enum.

Also, you say that you want “represent Strings as enum” but you are really wanting to represent User Agents as enums. Representing User Agents with enums is much more flexible and informative than your alternative: representing User Agents as Strings.

YOUR VIEW POINT
NAME : (REQUIRED)
MAIL : (REQUIRED)
will not be displayed
WEBSITE : (OPTIONAL)
YOUR
COMMENT :