How to Enhance Java Enums With Individual Behavior

This week I learned a neat trick how Java enums can define behavior which differs for each enum value.

As said before I’m a big fan of Java enums and use them quite often. Nevertheless I missed a cool feature which I saw this week when reading someone else’s code: it’s possible to give each enum value an individual behavior in a completely natural way.

A Simple Example

The following not really useful example should illustrate everything:

import java.util.function.BiFunction;

public enum IntOperator
        implements BiFunction<Integer, Integer, Integer>
{
  /** Addition operator. */
  Addition('+') {
    public Integer apply(Integer a, Integer b) { return a + b; }
  },
  /** Subtraction operator. */
  Subtraction('-') {
    public Integer apply(Integer a, Integer b) { return a - b; }
  },
  /** Multiplication operator. */
  Multiplication('*') {
    public Integer apply(Integer a, Integer b) { return a * b; }
  },
  /** Division operator. */
  Division('/') {
    public Integer apply(Integer a, Integer b) { return a / b; }
  };

  /** The symbol used for the operator. */
  public final char symbol;

  IntOperator(char symbol)
  {
    this.symbol = symbol;
  }

  @Override
  public String toString()
  {
    return Character.toString(operatorSymbol);
  }
}

The code above defines the four basic arithmetic operations as four enum values, and each can perform the given operation and return the result. The latter is coded by making the enum implement BiFunction<Integer, Integer, Integer>. The implementation of the interface is done for each value indidually and not at class level.

As said the class is not really useful, but nevertheless here’s an example using it:

public static void print(int a, IntOperator operator, int b)
{
  System.out.printf("%d %s %d = %d\n", a, operator, b, operator.apply(a, b));
}

Other Useful Things

Enums With Abstract Methods

It is also possible to add an abstract class level method and let the values implement that instead of implementing some interface. This method does not have to be public.

In the above example defining an public abstract int apply(int a, int b); method on class level would also work and remove the basically unnecessary boxing/unboxing introduced by the functional interface.

Default Behavior

Also possible is it to add a default implementation of a method on class level, and let only some values override this. Obviously this also works for methods implementing an interface method.

Override Standard Methods

Last not least it is possible for any value to override standard methods, although basically only toString() seems useful here.

But if most of your enum values can be named naturally with only a few exceptions because of special signs in the name which are not allowed in a Java identifier this is very useful:

public enum City
{
  Chicago,
  Detroit,
  NewYork {
    @Override
    public String toString()
    {
      return "New York";
    }
  },
  Washington
}