Enumerated values.
A way to define efficient enumerated values.
I.e. when there is a complete set of immutable values are known at compile time.
public enum Direction {
NORTH,
EAST,
SOUTH,
WEST;
}
Type safety. The enum class is a type that is distinct from other enums.
You can attach extra information to enum values.
Each value knows its own name.
Enum classes can have methods and can implement interfaces.
Efficient EnumSet
s.
public interface Directions {
public static final int NORTH = 0;
public static final int EAST = 1;
public static final int SOUTH = 2;
public static final int WEST = 3;
}
This is not great because there’s no type safety.
public void whatever(int direction)
What happens if we pass something that’s not one of the Direction
values?
public enum Color {
WHITE(1, 1, 1),
BLACK(0, 0, 0),
RED(1, 0, 0),
GREEN(0, 1, 0),
BLUE(0, 0, 1);
private double red;
private double green;
private double blue;
private Color(double red, double green, double blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
public String hexcode() {
return "%02x%02x%02x".formatted(
(int)(red * 255),
(int)(green * 255),
(int)(blue * 255));
}
}
package gigamonkey;
import static gigamonkey.Direction.*;
public class Foo {
public static void main(String[] args) {
System.out.println(NORTH.name());
System.out.println(NORTH); // toString() returns the name
}
}
In the Direction
enum from my dungeon code:
public Direction opposite() {
return Direction.class.getEnumConstants()[(ordinal() + 2) % 4];
}
public enum Ops implements DoubleBinaryOperator {
PLUS {
public double applyAsDouble(double left, double right) {
return left + right;
}
},
MINUS {
public double applyAsDouble(double left, double right) {
return left - right;
}
},
TIMES {
public double applyAsDouble(double left, double right) {
return left * right;
}
},
DIVIDE {
public double applyAsDouble(double left, double right) {
return left / right;
}
};
}
public enum Ops implements DoubleBinaryOperator {
PLUS((a, b) -> a + b),
MINUS((a, b) -> a - b),
TIMES((a, b) -> a * b),
DIVIDE((a, b) -> a / b);
private DoubleBinaryOperator op;
Ops(DoubleBinaryOperator op) {
this.op = op;
}
public double applyAsDouble(double left, double right) {
return op.applyAsDouble(left, right);
}
}
private static final Map<String, String> abbrevs = ...;
public static Optional<Direction> fromString(String name) {
try {
String key = name.toUpperCase();
key = abbrevs.getOrDefault(key, key);
return Optional.of(Direction.valueOf(key));
} catch (IllegalArgumentException iae) {
return Optional.empty();
}
}
EnumSet
A Set
implementation that is very efficient for enums that have 64 or fewer elements.
EnumSet<Direction> NS = EnumSet.of(NORTH, SOUTH);
NS.contains(NORTH) ==> true
NS.contains(WEST) ==> false
This basically boils down to some bit twiddling to map the enum values to individual bits in a long
.
There’s also an EnumMap
that takes a particular kind of enum as the key and which is likely more efficient than a HashMap
.
Class | Plain vanilla class that we’re used to. |
Interface | Defines a set of methods but has no data. |
Record | Concise immutable class with a bunch of free goodies (equals , hashCode) |
Enum | Immutable and a known set of instances. |