Java Enumerations

In this article I’ll write about Java Enumerations which are the most elegant way to define and use constants in your application.

This is the basic feature every one knows but there are some more which you might don’t know.

Why should I care?

Well, you use enums in your Java code. If you don’t then you do something wrong or have very simple applications without much complex functionality.

Anyway, let’s look at the basics. For example you want to have a class which uses workdays. You could define it like this:

    public class Schedule {
      private ??? workday;
    }

To store the workdays, let’s create a utility class which stores constants for the workdays:

public class Workdays {
  public static final String MONDAY = "Monday";
  public static final String TUESDAY = "Tuesday";
  public static final String WEDNESDAY = "Wednesday";
  public static final String THURSDAY = "Thursday";
  public static final String FRIDAY = "Friday";
}

Now the Schedule class will look like this:

public class Schedule {
  // Workdays.MONDAY, Workdays.TUESDAY
  // Workdays.WEDNESDAY, Workdays.THURSDAY
  // Workdays.FRIDAY
  private String workday;
}

I guess you see the flaw of this approach: You can easily set workday to "Saturday" or "Sunday" even if it is not defined in the Workdays class. This solution is not value-safe. And this is not what we want to achieve.

To solve this problem let’s convert the Workdays class to an enum:

public enum Workday {
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
}

Less typing required and now the solution is value-safe. We only have to adapt our Schredule class:

public class Schedule {
  private Workday workday;

  public Workday getWorkday() {
    return this.workday;
  }

  public void setWorkday(Workday workday) {
    this.workday = workday;
  }
}

Enums in conditionals

Enums are a good fit into conditional expressions (if statements or switch blocks). The nice thing about enums is that they are constant values so you can compare them with the == operator which is more elegant than using equals() — and it avoids possible NullPointerExceptions. And by the way: if you look at the implementation of equals() of the Enum class you will see the following:

~~~~~~~{“language”:”java”}
public final boolean equals(Object other) {
return this==other;
}
~~~~~~~

So use == freely because this is the default implementation of equals().

Let’s see examples how to use them:

if(currentSchedule.getWorkday() == Workday.FRIDAY) {
  System.out.println("Hurray! Tomorrow is weekend!");
}

Or in a switch block:

switch(currentSchedule.getWorkday()) {
  case MONDAY:
  case TUESDAY:
  case WEDNESDAY:
  case THURSDAY:
    System.out.println("Working and working and...");
    break;
  case FRIDAY:
    System.out.println("Hurray! Tomorrow is weekend!");
    break;
  default:
    System.out.println("Unknown day -.-");
}

Iterating enums

Iterating enums is quite simple. The class Enum defines a method called values() which returns you the values of the given enum. The best is to look at an example:

for(Workday w : Workday.values()) {
  System.out.println(w.name());
}

The example above will result in the following output:

MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY

As you can see, the order of the values() is the same as defined in the enum itself. So Java does not do any magic sorting.

Enum fields

Sometimes you want to simply print the enums to the console (or display them in a kind of UI). In the example above (Workday) you could simply use the name of the enumeration, although sometimes “TUESDAY” seems like shouting and “Tuesday” would be more preferred. In this case you can add and use custom fields of Enum objects:

public enum Workday {
  MONDAY("Monday"),
  TUESDAY("Tuesday"),
  WEDNESDAY("Wednesday"),
  THURSDAY("Thursday"),
  FRIDAY("Friday");

  private final String representation;

  private Workday(String representation) {
    this.representation = representation;
  }
}

As you can see in the example above the Enum gets a private field, in this case called representation. This field is final so it cannot be changed later on which implies that this property has to be initialized during construction of the enum. And this is done with a constructor and the constructor arguments are provided along with the enum definition.

You can have as many properties / fields in an enum as you wish however I suggest you keep this amount low because it would be really strange to have an enumeration with 15 extra properties. In such cases I would consider having a class and / or multiple enumerations to hold the same information.

Enum methods

Enum fields are something good but how to access the field? I told you this new representation is to represent the value of this enum however currently we cannot access the property outside of the enumeration itself.

Beside this there is a basic method available to all enums: name() which returns the name of the current value as a String. This means in the basic case you can use this method to display the value of the enum (for example in the UI or in a log entry). Of course the toString() function exists too however sometimes this is overridden from the developers to have a more programmer-friendly (or user-friendly?) display. As a best practice I suggest you use the name() method instead of the toString() if you want to display the name of the enumeration.

To change the representation example from above (when we iterated through the values()) simply write a function which returns the new variable representation and use it in the iteration:

public enum Workday {
  MONDAY("Monday"),
  TUESDAY("Tuesday"),
  WEDNESDAY("Wednesday"),
  THURSDAY("Thursday"),
  FRIDAY("Friday");

  private final String representation;

  private Workday(String representation) {
    this.representation = representation;
  }

  public String getRepresentation() {
    return this.representation;
  }
}

Now update the iteration:

for(Workday w : Workday.values()) {
  System.out.println(w.getRepresentation());
}

This results now in the following:

Monday
Tuesday
Wednesday
Thursday
Friday

However this is not the only usage where you can implement own methods for enums. In the next section we will see how we can map Enum values to Strings and back.

Implementing interfaces

One thing which is less-known about enums is that they can implement interfaces. This means if you need common functionality along diverse enumerations you can define it with an interface and the enums have to implement the methods in the interface.

One such use case would be storing enum values in a database with JPA — although not by name or ordinal (as available through @Enumeration and EnumType) but through a short code.

In this case you can create an interface holding the methods which convert the enum to the database representation and which converts the enumeration back.

public interface DatabaseEnum<T extends Enum> {

    /**
     * Converts the database representation back to the enumeration value
     */
    T fromDatabase(String representation);

    /**
     * Converts the enum value to the database representation
     */
    String toDatabaseString();

}

This interface uses generics (represented by the T type) and converts between Strings and the enumeration type.

To implement this interface let’s extend the Workday example:

public enum Workday implements DatabaseEnum{
  MONDAY("Monday"),
  TUESDAY("Tuesday"),
  WEDNESDAY("Wednesday"),
  THURSDAY("Thursday"),
  FRIDAY("Friday");

  private final String representation;

  private Workday(String representation) {
    this.representation = representation;
  }

  public String getRepresentation() {
    return this.representation;
  }

  @Override
  public String toDatabaseString() {
    return this.representation;
  }

  @Override
  public Workday fromDatabase(String representation) {
    for(Workday wd: Workday.values()) {
      if(wd.representation.equals(representation)) {
        return wd;
      }
    }
    return null;
  }
}

Using an enum instead of a boolean

Sometimes you end up with a method which takes a boolean expression (or you just get a project specification which tells you to use a boolean but it feels quite itchy). In this case feel free to introduce a new enum and use the right value instead of the boolean.

For example once I have had a specification which told me that I have to create a method which takes some parameters and a boolean which is called “rightHandSide”. And actually the default value of “rightHandSide” was false. First I implemented the method as the specification told me however it was uncomfortable for me and I thought it should be another way to get rid of this cold feeling whenever I looked at the method:

public void someMethod(String someParameter, boolean rightHandSide) {
  if(!rightHandSide) {
    // do something
  }
}

Well, it does not seem bad but how about extending the functionality? What if the side should not matter? In this case the method could be extended with other boolean parameters but it won’t do the trick in the long run. And because the default of “rightHandSide” was false I needed to create a call where the parameter wasn’t provided and it called the default method with false.

So I introduced a new enumeration called Side and replaced the boolean parameter:

public enum Side {
  RIGHT_HAND,
  LEFT_HAND
}

public void someMethod(String someParameter, Side side) {
  if(side == Side.RIGHT_HAND) {
    // do something
  }
}

Now it feels much better and the method can be extended to more cases later on.

Conclusion

As you can see Enums are a good fit to replace constants — and sometimes boolean method arguments too.

Advertisements

One thought on “Java Enumerations

  1. Pingback: More on Java Enumerations | JaPy Software

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s