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
}