Create enumerated constants in Java

The weaknesses of Java's static finals are defined here and a template is provided for creating typesafe constants

A set of "enumerable constants" is an ordered collection of constants that can be counted, like numbers. That property lets you use them like numbers to index an array, or you can use them as the index variable in a for loop. In Java, such objects are most often known as "enumerated constants."

Using enumerated constants can make code more readable. For example, you might want to define a new data type named Color with constants RED, GREEN, and BLUE as its possible values. The idea is to have Color as an attribute of other objects you create, such as Car objects:

  class Car {
     Color color;
     ...
  }

Then you can write clear, readable code, like this:

  myCar.color = RED;

instead of something like:

  myCar.color = 3;

An even more important attribute of enumerated constants in languages like Pascal is that they are type safe. In other words, it is not possible to assign an invalid color to the color attribute -- it must always be either RED, GREEN, or BLUE. In contrast, if the color variable were an int, then you could assign any valid integer to it, even if that number did not represent a valid color.

This article gives you a template for creating enumerated constants that are:

  • Type safe
  • Printable
  • Ordered, for use as an index
  • Linked, for looping forwards or backwards
  • Enumerable

In a future article, you will learn how to extend enumerated constants to implement state-dependent behavior.

Why not use static finals?

A common mechanism for enumerated constants uses static final int variables, like this:

  static final int RED = 0;
  static final int GREEN = 1;
  static final int BLUE = 2;
  ...

Static finals are useful

Because they are final, the values are constant and unchangeable. Because they are static, they are only created once for the class or interface in which they are defined, instead of once for every object. And because they are integer variables, they can be enumerated and used as an index.

For example, you can write a loop to create a list of a customer's favorite colors:

  for (int i=0; ...) {
    if (customerLikesColor(i)) {
       favoriteColors.add(i);
    }
  }

You can also index into an array or a vector using the variables to get a value associated with the color. For example, suppose you have a board game that has different colored pieces for each player. Let's say you have a bitmap for each color piece and a method called display() that copies that bitmap to the current location. One way to put a piece on the board might be something like this:

PiecePicture redPiece = new PiecePicture(RED); PiecePicture greenPiece = new PiecePicture(GREEN); PiecePicture bluePiece = new PiecePicture(BLUE);

void placePiece(int location, int color) { setPosition(location); if (color == RED) { display(redPiece); } else if (color == GREEN) { display(greenPiece); } else { display(bluePiece); } }

But by using the integer values to index into an array of pieces, you can simplify the code to:

  PiecePicture[] piece = {new PiecePicture(RED), 
                          new PiecePicture(GREEN), 
                          new PiecePicture(BLUE) 
                         };
  void placePiece(int location, int color) {
    setPosition(location);
    display(piece[color]);
  }

Being able to loop over a range of constants and index into an array or vector are the major advantages of static final integers. And when the number of choices grows, the simplification effect is even greater.

But static finals are risky

Still, there are a couple of drawbacks to using static final integers. The major drawback is the lack of type safety. Any integer that is calculated or read in can be used as a "color," regardless of whether it makes sense to do so. You can loop right past the end of the defined constants or stop short of covering them all, which can easily happen if you add or remove a constant from the list but forget to adjust the loop index.

For example, your color-preference loop might read like this:

  for (int i=0; i <= BLUE; i++) {
    if (customerLikesColor(i)) {
       favoriteColors.add(i);
    }
  }

Later on, you might add a new color:

  static final int RED = 0;
  static final int GREEN = 1;
  static final int BLUE = 2;
  static final int MAGENTA = 3;

Or you might remove one:

  static final int RED = 0;
  static final int BLUE = 1;

In either case, the program will not operate correctly. If you remove a color, you will get a runtime error that draws attention to the problem. If you add a color, you won't get any error at all -- the program will simply fail to cover all of the color choices.

Another drawback is the lack of a readable identifier. If you use a message box or console output to display the current color choice, you get a number. That makes debugging pretty difficult.

The problems creating a readable identifier are sometimes solved using static final string constants, like this:

  static final String RED = "red".intern();
  ...

Using the intern() method guarantees there is only one string with those contents in the internal string pool. But for intern() to be effective, every string or string variable that is ever compared to RED must use it. Even then, static final strings do not allow for looping or for indexing into an array, and they still do not address the issue of type safety.

Type safety

The problem with static final integers is that the variables that use them are inherently unbounded. They are int variables, which means they can hold any integer, not just the constants they were intended to hold. The goal is to define a variable of type Color so that you get a compilation error rather than a runtime error whenever an invalid value is assigned to that variable.

An elegant solution was provided in Philip Bishop's article in JavaWorld, "Typesafe constants in C++ and Java."

The idea is really simple (once you see it!):

public final class Color { // final class!! private Color() {} // private constructor!!

public static final Color RED = new Color(); public static final Color GREEN = new Color(); public static final Color BLUE = new Color(); }

Because the class is defined as final, it can't be subclassed. No other classes will be created from it. Because the constructor is private, other methods can't use the class to create new objects. The only objects that will ever be created with this class are the static objects the class creates for itself the first time the class is referenced! This implementation is a variation of the Singleton pattern that limits the class to a predefined number of instances. You can use this pattern to create exactly one class any time you need a Singleton, or use it as shown here to create a fixed number of instances. (The Singleton pattern is defined in the book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides, Addison-Wesley, 1995. See the Resources section for a link to this book.)

The mind-boggling part of this class definition is that the class uses itself to create new objects. The first time you reference RED, it doesn't exist. But the act of accessing the class that RED is defined in causes it to be created, along with the other constants. Admittedly, that kind of recursive reference is rather difficult to visualize. But the advantage is total type safety. A variable of type Color can never be assigned anything other than the RED, GREEN, or BLUE objects that the Color class creates.

Identifiers

The first enhancement to the typesafe enumerated constant class is to create a string representation of the constants. You want to be able to produce a readable version of the value with a line like this:

  System.out.println(myColor);

Whenever you output an object to a character output stream like System.out, and whenever you concatenate an object to a string, Java automatically invokes the toString() method for that object. That's a good reason to define a toString() method for any new class you create.

If the class does not have a toString() method, the inheritance hierarchy is inspected until one is found. At the top of the hierarchy, the toString() method in the Object class returns the class name. So the toString() method always has some meaning, but most of the time the default method will not be very useful.

Here is a modification to the Color class that provides a useful toString() method:

public final class Color { private String id; private Color(String anID) {this.id = anID; } public String toString() {return this.id; }

public static final Color RED = new Color(

"Red"

); public static final Color GREEN = new Color(

"Green"

); public static final Color BLUE = new Color(

"Blue"

); }

This version adds a private String variable (id). The constructor has been modified to take a String argument and store it as the object's ID. The toString() method then returns the object's ID.

One trick you can use to invoke the toString() method takes advantage of the fact that it is automatically invoked when an object is concatenated to a string. That means you could put the object's name in a dialog by concatenating it to a null string using a line like the following:

  textField1.setText("" + myColor);

Unless you happen to love all the parentheses in Lisp, you will find that a bit more readable than the alternative:

  textField1.setText(myColor.toString());

It's also easier to make sure you put in the right number of closing parentheses!

Ordering and indexing

The next question is how to index into a vector or an array using members of the

Color

class. The mechanism will be to assign an ordinal number to each class constant and reference it using the attribute

.ord

, like this:

  void placePiece(int location, int color) {
    setPosition(location);
    display(piece[color.ord]);
  }

Although tacking on .ord to convert the reference to color into a number is not particularly pretty, it is not terribly obtrusive either. It seems like a fairly reasonable tradeoff for typesafe constants.

Here is how the ordinal numbers are assigned:

public final class Color { private String id; public final int ord; private static int upperBound = 0; private Color(String anID) { this.id = anID; this.ord = upperBound++; } public String toString() {return this.id; } public static int size() { return upperBound; }

public static final Color RED = new Color("Red"); public static final Color GREEN = new Color("Green"); public static final Color BLUE = new Color("Blue"); }

This code uses the new JDK version 1.1 definition of a "blank final" variable -- a variable that is assigned a value once and once only. This mechanism allows each object to have its own non-static final variable, ord, which will be assigned once during object creation and which will thereafter remain immutable. The static variable upperBound keeps track of the next unused index in the collection. That value becomes the ord attribute when the object is created, after which the upper bound is incremented.

For compatibility with the Vector class, the method size() is defined to return the number of constants that have been defined in this class (which is the same as the upper bound).

A purist might decide that the variable ord should be private, and the method named ord() should return it -- if not, a method named getOrd(). I lean toward accessing the attribute directly, though, for two reasons. The first is that the concept of an ordinal is unequivocally that of an int. There is little likelihood, if any, that the implementation would ever change. The second reason is that what you really want is the ability to use the object as though it were an int, as you could in a language like Pascal. For example, you might want to use the attribute color to index an array. But you cannot use a Java object to do that directly. What you would really like to say is:

  display(piece[color]); // desirable, but does not work

But you can't do that. The minimum change necessary to get what you want is to access an attribute, instead, like this:

  display(piece[color.ord]); // closest to desirable

instead of the lengthy alternative:

  display(piece[color.ord()]); // extra parentheses

or the even lengthier:

  display(piece[color.getOrd()]); // extra parentheses and text

The Eiffel language uses the same syntax for accessing attributes and invoking methods. That would be the ideal. Given the necessity of choosing one or the other, however, I've gone with accessing ord as an attribute. With any luck, the identifier ord will become so familiar as a result of repetition that using it will seem as natural as writing int. (As natural as that may be.)

Looping

The next step is being able to iterate over the class constants. You want to be able to loop from beginning to end:

  for (Color c=Color.first(); c != null; c=c.next()) {
    ...
  }

or from the end back to the beginning:

  for (Color c=Color.last(); c != null; c=c.prev()) {
    ...
  }

These modifications use static variables to keep track of the last object created and link it to the next object:

public final class Color { private String id; public final int ord; private Color prev; private Color next;

private static int upperBound = 0; private static Color first = null; private static Color last = null; private Color(String anID) { this.id = anID; this.ord = upperBound++; if (first == null) first = this; if (last != null) { this.prev = last; last.next = this; } last = this; } public String toString() {return this.id; } public static int size() { return upperBound; } public static Color first() { return first; } public static Color last() { return last; } public Color prev() { return this.prev; } public Color next() { return this.next; }

public static final Color RED = new Color("Red"); public static final Color GREEN = new Color("Green"); public static final Color BLUE = new Color("Blue"); }

Whenever a new constant object is created, it is linked to the last constant object, and the last constant object is linked to it. The static methods first() and last() return the end points of the list, while the methods prev() and next() move from object to object within the list. The beauty of all this is that once the class is set up, you only have to modify the last few lines to create or remove constants from the class; their order is determined by the order in which you create them.

Enumerations

The last modification is to extend the class so that you can use a standard Enumeration interface, like this:

  import java.util.*;
  ...
  Enumeration e = Color.elements();
  while (e.hasMoreElements()) {
    Color c = (Color) e.nextElement();
    ...
  }

The Enumeration interface is defined in java.util, so that package needs to be imported. The interface says that the object has two methods. One method, hasMoreElements(), returns a boolean. The other, nextElement(), returns an object of type Object -- which forces you to cast it to an object of type Color using (Color) in order to assign the value to a Color variable.

The really cool and largely unsung merit of interfaces is that you can use an interface as a data type! The elements method in Color will return an object, and that object will belong to a special class. But the user won't even care what that class is! The only relevant feature of the class will be that it implements the Enumeration interface. The method invoking the class can then write:

  Enumeration e = Color.elements();

regardless of what the actual class is that elements() returns.

Here are the modifications necessary to return a class that implements the Enumeration interface:

import java.util.*;

public final class Color { private String id; public final int ord; private Color prev; private Color next;

private static int upperBound = 0; private static Color first = null; private static Color last = null; private Color(String anID) { this.id = anID; this.ord = upperBound++; if (first == null) first = this; if (last != null) { this.prev = last; last.next = this; } last = this; } public static Enumeration elements() { return new Enumeration() { private Color curr = first; public boolean hasMoreElements() { return curr != null; } public Object nextElement() { Color c = curr; curr = curr.next(); return c; } }; } public String toString() {return this.id; } public static int size() { return upperBound; } public static Color first() { return first; } public static Color last() { return last; } public Color prev() { return this.prev; } public Color next() { return this.next; }

public static final Color RED = new Color("Red"); public static final Color GREEN = new Color("Green"); public static final Color BLUE = new Color("Blue"); }

This code uses an "anonymous (inner) class." Both anonymous classes and inner classes are new in Java 1.1. An inner class is a class that is defined inside of another class -- so it cannot be used outside of that class. An anonymous class is one without a name -- a "one-shot" class that is used to instantiate a single object. An anonymous class can be used either to extend an existing class or to implement an interface. In this case, it implements the Enumeration interface. The "new" operator creates a new object using the definition in the curly braces that follow it.

When an inner class references a local variable from the containing class, that variable must be declared as final. That restriction is imposed by Java so that the virtual machine and compiler do not have to worry about a variable that could be simulatenously modified in two different classes. In this case, the only such variable accessed is first, which just happens to be final.

Conclusion

In this article, you have learned how to create typesafe constants that are ordered, enumerable, printable, usable as an index, and usable in a loop. Below is the complete template for constants that meet these criteria. It's a fairly hefty chunk of code, but it is a useful template: If you do a search and replace on "Color" you can create any class of constants you like. Then you need only modify the last few lines to define the constants you need. Copy this template and modify the parts that are highlighted:

package enumTest; import java.util.*;

public final class Color { private String id; public final int ord; private Color prev; private Color next;

private static int upperBound = 0; private static Color first = null; private static Color last = null; private Color(String anID) { this.id = anID; this.ord = upperBound++; if (first == null) first = this; if (last != null) { this.prev = last; last.next = this; } last = this; } public static Enumeration elements() { return new Enumeration() { private Color curr = first; public boolean hasMoreElements() { return curr != null; } public Object nextElement() { Color c = curr; curr = curr.next(); return c; } }; } public String toString() {return this.id; } public static int size() { return upperBound; } public static Color first() { return first; } public static Color last() { return last; } public Color prev() { return this.prev; } public Color next() { return this.next; }

public static final

Color

RED

= new

Color

("

Red

"); public static final

Color

GREEN

= new

Color

("

Green

"); public static final

Color

BLUE

= new

Color

("

Blue

"); }

Finally, here is a test file that shows what happens when you enumerate over the constants defined in the Color class:

package enumTest; import java.util.*;

public class EnumTest { //Main method static public void main(String[] args) { Enumeration e = Color.elements(); while (e.hasMoreElements()) { Color c = (Color) e.nextElement(); System.out.println(c + ": " + c.ord); } } }

Note: If compilation produces the error, "class Color not found," make sure your classpath variable includes "..". With the Color class in the enumTest package, the compiler sees "Color" as "enumTest.Color." The installation instructions for JDK 1.1 say to include "." in the classpath, but under Windows, at least, that causes the compiler to look for Color.java under the current directory (enumTest) instead of in that directory.

Eric Armstrong has been programming and writing professionally since before there were personal computers. His production experience includes AI programs, system libraries, real-time programs, and business applications in a variety of languages. He is currently writing a book on a soon-to-be-released Java IDE.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies