Enums

Enumerated values.

Another way to define a class

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;
}

Advantages of enums

  • 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 EnumSets.

What we used to do

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?

Data in enums

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));
  }
}

Enum names

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
  }
}

Example of a method

In the Direction enum from my dungeon code:

public Direction opposite() {
  return Direction.class.getEnumConstants()[(ordinal() + 2) % 4];
}

Implementing an interface

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;
    }
  };
}

Another way

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);
  }
}

Also static methods

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.

Kinds of class-like things

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.