Enumerated types (enums) are a way to define fixed set of constants, so helpful in many areas of software development. In the most common case, in your Java code written for Java 5 or newer, you will use enums for int constants and replace chunks of code that look like this
public static final int DIRECTION_NORTH = 0;
public static final int DIRECTION_SOUTH = 1;
public static final int DIRECTION_EAST = 2;
public static final int DIRECTION_WEST = 3;
with something like this
public enum Direction {
NORTH, SOUTH, EAST, WEST;
}
Then, you’ll change method definitions that look like
public void changeDirection(int direction) {
// do something
}
with something like this
public void changeDirection(Direction direction) {
// do something
}
And finally, the method call will be changed too, from
ship.changeDirection(DIRECTION_EAST);
to
ship.changeDirection(Direction.NORTH);
There are a few obvious benefits from using enums over the standard int constants, such as the type safety and namespaces for example.
But we can also use enums to define other types of constants, string constants for example. You can often see examples of using enums to make a switch idiom for strings possible in Java. Take a look at the following example
String direction = "WEST";
switch (Direction.valueOf(direction)) {
case WEST : System.out.println("Go west!");
break;
case EAST : System.out.println("Go east!");
break;
default : System.out.println("Go somewhere!");
}
It prints Go west! as a result which is great.
But in order to be truly useful for string constants purpose, enums needs some extra tuning and here’s why.
As the JavaDoc of the valueOf method used above says:
The name must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
So if you want your switch work well you need to be sure that you’ve passed a string with the value exact to some of the identifiers defined in the enum. So if you change your direction variable value to west, you’ll get the following exception
Exception in thread "main" java.lang.IllegalArgumentException:
No enum const class net.scriptinginjava.test.EnumTest$Direction.west
at java.lang.Enum.valueOf(Enum.java:192)
at net.scriptinginjava.test.EnumTest$Direction.valueOf(EnumTest.java:1)
at net.scriptinginjava.test.EnumTest.main(EnumTest.java:28)
which could be tricky in some situations.
Another scenario where enums could benefit from extra customization is when you have to have a kind of string mapping between identifiers and their values. Take for example that you want to deal with HTTP headers in this way. You cannot use names like if-modified-since as an enum identifier since it is not a regular Java variable name so some kind of transformation is needed and the question is, what can we do to customize enums?
As we have seen earlier enums extend java.lang.Enum class so we can start looking there for enhancements we need. In order to customize represenation of strings in our enum, we need to pay attention to two methods:
toString- which prints the value of a constant. By default, this method returns the exact name of the constant identifier, just as thenamemethod.valueOf- which returns a enum value from a string. Unfortunately, this method cannot be overridden so we have to find a workaround for converting custom strings to enum values without usingvalueOfmethod.
Now, take a look at the following enum declaration
public enum HttpHeader {
IF_MODIFIED_SINCE, USER_AGENT, UNKNOWN;
public String toString() {
return name().replaceAll("_", "-").toLowerCase();
}
public static HttpHeader getValue(String value) {
try {
return valueOf(value.replaceAll("-", "_").toUpperCase());
} catch (Exception e) {
return UNKNOWN;
}
}
}
The first thing to notice is that we defined uppercased values with “_” char as a word separator. It’s kind of a “good practice” so let it be. Now take a look at the toString method, which replaces _ with - in the name and returns such modified value. So, the following line
System.out.println(HttpHeader.IF_MODIFIED_SINCE);
will print if-modified-since value.
Now let’s see how to use the switch statement with this enum. Take a look at this example
String[] headers = new String[]{"if-modified-since", "User-Agent", "test"};
for (String header : headers) {
switch (HttpHeader.getValue(header)) {
case IF_MODIFIED_SINCE :
System.out.println("if-modified-since header found");
break;
case USER_AGENT :
System.out.println("user-agent header found");
break;
case UNKNOWN :
default :
System.out.println("unkown header found: " + header);
}
}
It will print the following output
if-modified-since header found
user-agent header found
unkown header found: test
As you can see, this enum has a greater flexibility in matching strings to enum constants. Also, you can note that now we can gracefully fail if the passed string does not match any value. It returns the UNKNOWN value instead of throwing an exception. Of course, whether this is a desirable funcionality depends on your requirements and design.
In the previous example, we used a simple transformation in the toString method to customize the value of the printed constant. In case that you have needs for more complex transformation you can apply another technique. Take a look at this example:
public enum HttpHeader {
IF_MODIFIED_SINCE("If-Modified-Since"),
USER_AGENT("User-Agent"),
UNKNOWN("");
private String realName;
private HttpHeader(String realName) {
this.realName = realName;
}
public String toString() {
return realName;
}
public static HttpHeader getValue(String value) {
try {
return valueOf(value.replaceAll("-", "_").toUpperCase());
} catch (Exception e) {
return UNKNOWN;
}
}
}
This enum definition defines a constructor with a string parameter. We can use this parameter to define a string representation of the constant. So now, the code snippet
System.out.println(HttpHeader.IF_MODIFIED_SINCE);
will print the following output
If-Modified-Since
Everything else remains the same as in our previous examples.
Customized like this, enums could be used for dealing with string constants, which could be helpful in processing header names (and values) for example.



Thanks for the post Dejan...
We had been looking at ways of doing something similar with our enums. I will have to give this approach a shot in the future.
We actually use enums a lot of times for List of Values. And using the Enum instance name isn't always easy. For instance we have an Enum called CarType with TWO_DOOR and FOUR_DOOR. We don't want to display those strings to the user. So instead of doing like you have done, we actually attach strings to our Enums and call them messages.
public enum CarType {
TWO_DOOR("2 Door"),FOUR_DOOR("4 Door");
private String message;
CarType(String message){
this.message = message;
}
public getMessage() {
return this.message;
}
}
The advantage I see this way is we have more flexibility in our string. If you have a long string you want to display, your Enum instance name doesn't have to have a super long, capitalized, separated by underscores id. Another reason we have done this is for internationalization. We can put our i18n message key as the enum's message, and then when we display on our jsp's we can translate them.
Thanks again for your post...
-- Nick
It's worth to mention that we can use a syntax known from anonymous inner classes as well:
public enum HttpHeader
{
IF_MODIFIED_SINCE() { @Override public String toString() { return "If-Modified-Since"; } },
USER_AGENT() { @Override public String toString() { return "User-Agent"; } },
UNKNOWN() { @Override public String toString() { return ""; } };
public static HttpHeader getValue( String value )
{
try
{
return valueOf( value.replaceAll( "-", "_" ).toUpperCase() );
}
catch ( Exception e )
{
return UNKNOWN;
}
}
}
Bye, Christian | tutego
This is superb article, Java is all in all Language.
Excellent contribution. Just a quick addition to mention that it is worth to mention that separating the enumeration from the name resolution can be very useful to integrate with ORM tools like Hibernate. I short example can be found at : Persisted enumerations in Hibernate