Enums

Contact Us or call 1-877-932-8228
Enums

Enums

In Java 5, the enum element was introduced. Long sought by the C/C++ part of the Java community, enums provide a set of predefined constants for indicating a small set of mutually exclusive values or states.

Why Another Syntax Element for a Set of Constants?

The other approaches all have some sort of flaw, particularly as involves type-safety.

  • Interfaces defining only constants were commonly used, and several are grandfathered into the API, like SwingConstants. But, there is a minor problem that if you implement an interface in order to gain the constants, you then have additional public elements in that class that you wouldn't really want to provide to the outside world.
    public class MyFrame extends JFrame implements SwingConstants { . . . }
    
    MyFrame frame = new MyFrame();
    // frame.HORIZONTAL is now publicly available
    
    While not terrible, there isn't any real meaning to frame.HORIZONTAL, or any reason we would want to make it available to the outside world.
  • Using plain old integers seems straightforward enough, but, if you perhaps have a method that requires one of that set of values to be passed in, the parameter would be typed as int. A caller could supply any int value, including ones you wouldn't expect.
    private int LEFT = 0;
    private int RIGHT = 1;
    private int CENTER = 2;
    
    public void setAlignment(int align) { ... }
    
    // compiler would allow:
    setAlignment(99);

Java enums provide a type-safe way of creating a set of constants, since they are defined as a class, and therefore are a type of data.

A disadvantage to this approach is that the set of values is written into the code. For sets of values that may change, this would require recompiling the code, and would invalidate any serialized instances of the enum class. For example, if we offered a choice of benefits plans to our employees, the set of available plans would not be a good candidate for an enum, since it is likely that the set of available plans would eventually change.

Defining an enum Class

To create a simple enum class:

  1. Declare like an ordinary class, except using the keyword enum instead of class.
  2. Within the curly braces, supply a comma-separated list of names, ending in a semicolon.

One instance of the enum class will be created to represent each item you listed, available as a static field of the class, using the name you supplied which will be the individual values. Each instance can provide an integral value, with sequential indexes starting at 0, in the order that the names were defined - there is no way to change this, but there is a route to get specific values which have a complex internal state.

public enum EnumName {
	value1, value2, value3, . . . ;
}
public enum Alignment { left, right, center; }

There will be three instances of the class created, Alignment.left, Alignment.right, and Alignment.center. An Alignment type variable can hold any of these three values.

Enums automatically extend the Enum class from the API, and they inherit several useful methods:

  • Each object has a name method that returns the name of that instance (as does the toString method).
  • The ordinal method returns that enum object's position in the set, the integer index mentioned above.

There are also several other methods that will be present, although they are not listed in the documentation for Enum.

  • A public static EnumName[] values() method that returns an array containing all the values, in order (so that the array index would match the ordinal value for that object). This method is not inherited, but is built specifically for each enum class.
  • A public EnumName valueOf(String name) method that returns the instance whose name matches the specified name (this is not the uglier method you will see in the documentation, but another built specifically for each instance - the one listed in the documentation is actually used internally by the simpler form).

The reason for the last two methods not being in the documentation has to do with generics and type erasure - the methods cannot be declared in the Enum base class in a way that would allow the use of the as-yet unknown subclass.

Individual values from the set may be accessed as static elements of the enum class. The JVM will instantiate exactly one instance of each value from the set. Therefore, they can be used in comparisons with ==, or in switch statements (using the equals method is preferred to ==, since it will serve as a reminder that you are dealing with true objects, not integers).

Although enums may be top-level classes, they are often created as inner classes, as in the following example, where the concept of the enum is an integral part of a new BookWithEnum class. When used as an inner class, they are automatically static, so that an instance of an inner enum does not have access to instance elements of the enclosing class.

Code Sample:

Java-InnerClasses/Demos/BookWithEnum.java
public class BookWithEnum {
  private int itemCode;
  private String title;
  private double price;
  private Category category;
  
  public enum Category { required, supplemental, optional, unknown };
  
  public BookWithEnum(
        int itemCode, String title, 
        double price, Category category) {
    setItemCode(itemCode);
    setTitle(title);
    setPrice(price);
    setCategory(category);
  }
  public BookWithEnum(String title) {
    setItemCode(0);
    setTitle(title);
    setPrice(0.0);
    setCategory(Category.unknown);
  }
  public int getItemCode() {
    return itemCode;
  }
  public void setItemCode (int itemCode) {
    if (itemCode > 0) this.itemCode = itemCode; 
  }
  public String getTitle() {
    return title;
  }
  public void setTitle (String title) {
    this.title = title;
  }
  public void setPrice(double price) {
    this.price = price;
  }
  public double getPrice() {
    return price;
  }
  public void setCategory(Category category) {
    this.category = category;
  }
  public void setCategory(String categoryName) {
    this.category = Category.valueOf(categoryName);
  }
  public Category getCategory() {
    return category;
  }
  public void display() {
    System.out.println(itemCode + " " + title + ": " + category +
          ", Price: $" + price);
  }
}

The Category enum is defined as an inner class to BookWithEnum. The full names of the complete set of values are: BookWithEnum.Category.required, BookWithEnum.Category.supplemental, BookWithEnum.Category.optional, and BookWithEnum.Category.unknown. From within the BookWithEnum class, they may be accessed as: Category.required, Category.supplemental, Category.optional, and Category.unknown.

We set the category for a book constructed without one as Category.unknown, and provide methods to get the value, and to set it with either an enum object or from a string.

Note that enums may be used in switch statements - for the cases you use only the short name for the value.

More Complex Enums

Enums are more than just a set of integer constants. They are actually a set of unique object instances, and, as objects, can have multiple fields. So, an enum is a class with a fixed number of possible instances, each with it's own unique state, and each of the possible instances is created automatically and stored as static field under the same name. (In design pattern terms, an enum is a Flyweight - a class where only a limited number of fixed states exist.)

To create a more complex enum class:

  1. Declare as before.
  2. Declare any additional fields and accessor methods as with a regular class. While you can actually write mutator methods to create what is called a mutable enum, this practice is strongly discouraged.
  3. Write one constructor.
  4. Within the curly braces, again supply a comma-separated list of names, which will be the individual values, but this time with a parameter list. The enum values will be constructed with the data you provide.