Java 5 Enums

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

Externa

Internal

Overview

The standard way of representing an enumerated type in pre-5 Java was the "int Enum pattern":

public static final int COLOR_RED = 0;
public static final int COLOR_BLUE = 1;
public static final int COLOR_WHITE = 2;
...

Problems with this approach:

  • Not type safe any int value can be passed as a "color". There is no concept of "color" type.
  • No namespace you must prefix constants of an int enum with a string (in this case COLOR_) to avoid collisions with other int enum types.
  • Brittleness because int 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 are uninformative.

Java 5 added syntactic support for enumerated types:

public class Example {

    public enum Color { BLUE, RED, WHITE, BLACK };

    ....
}

The above declaration defines a full-fledged class, known as enum type.

When should we use enum?

Any time we need a fixed set of constants. That includes natural enumerated types (like the planets, days of the week, and suits in a card deck) as well as other sets where you know all possible values at compile time, such as choices on a menu, rounding modes, command line flags, and the like.

It is not necessary that the set of constants in an enum type stay fixed forever. The feature was specifically designed to allow for binary compatible evolution of enum types.

Features

  • Automatic compile-type checking
  • Enum types can implement arbitrary interfaces
  • Enum types provide high-quality implementations of all the Object methods
  • Enum types are Comparable and Serializable.
  • The serial form is designed to withstand arbitrary changes in the enum type.
  • Use values() to iterate over the values of an enum type:
for(Color c: Color.values())  {
    System.out.println(c);
}

Arbitrary behavior and state can be added to each enum element

public enum CompressionType {

  GZ  {

      public File compress(File srcFile, File destinationDir, String basename)  throws Exception  {
          // ...
      }
    
      public String getCompressedFileName(String filename)  {
          // ...
      }
   };

   public abstract File compress(File srcFile, File destinationDir, String basename) throws Exception;
   public abstract String getCompressedFileName(String filename);
};

Other example, an implementation of the HTTP Header:

public enum HttpHeader {
    Host,
    User_Agent,
    Accept,
    Accept_Language,
    Accept_Encoding,
    Accept_Charset,
    Keep_Alive,
    Connection;

    private String value;
    
    public String getValue() {
        return value;
    }
    
    public void setValue(String value) {
        this.value = value;
    }
}

Conversion of Strings to and from enums

valueOf()

Conversion from String to enum:

EnumType.valueOf(String)

If there is no enum corresponding to the specified string, valueOf() throws an IllegalArgumentException, with the message: "No enum const class ...."

Conversion of Custom Strings to enums

public enum InstanceOutputField {

    NAME("name"),
    PUBLIC_IP("public-ip");

    private String commandLineLiteral;

    InstanceOutputField(String commandLineLiteral)  {
        this.commandLineLiteral = commandLineLiteral;
    }

    public String getCommandLineLiteral() {
        return commandLineLiteral;
    }

    public static InstanceOutputField toInstanceOutputField(String commandLineLiteral)  {
        if (commandLineLiteral == null)  {
            throw new IllegalArgumentException("null command line literal");
        }

        if (NAME.getCommandLineLiteral().equalsIgnoreCase(commandLineLiteral))  {
            return NAME;
        }
        else if (PUBLIC_IP.getCommandLineLiteral().equalsIgnoreCase(commandLineLiteral)) {
            return PUBLIC_IP;
        }
        else {
            throw new IllegalArgumentException("no enum for '" + commandLineLiteral + "'");
        }
    }
}

Implementing enum that have an index

public enum PageState {

    NEW(0),
    ANALYZING(1);

    private int index;

    PageState(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }
}

The ordinal() Method

The java.lang.Enum.ordinal() method returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero).

enums and Interfaces

public interface Color {

    int getPreference();
}

public enum Colors implements Color {

    RED(0),
    BLUE(1);

    private int preference;

    Colors(int preference) {
        this.preference = preference'
    }

    public int getPreference() {
        return preference;
   }
}