Enums en Java
Define un conjunto fijo de constantes en Java con tipos enum, incluyendo enums con campos, constructores y métodos.
Un enum es una clase cuyas instancias son un conjunto fijo conocido en tiempo de compilación. Los días de la semana, los colores de un semáforo, los estados de un pedido — cualquier cosa donde los valores válidos sean una pequeña lista con nombre. Una vez que escribes enum Status { OPEN, CLOSED }, esos dos son los únicos valores de Status que existirán jamás, y el compilador te avisará si intentas inventar un tercero.
Los enums reemplazan el viejo hábito de C de public static final int OPEN = 0;. Las constantes enteras no ofrecen seguridad de tipos — setStatus(7) compila — pero setStatus(Status status) solo acepta uno de los valores declarados.
Declarar un enum
La forma más simple es simplemente una lista de nombres de constantes:
public enum Direction {
NORTH, EAST, SOUTH, WEST
}Úsalo como cualquier otro tipo:
Direction d = Direction.NORTH;
if (d == Direction.NORTH) System.out.println("heading up");Cada constante es una instancia singleton de Direction. Comparar con == es correcto e idiomático — solo existe un NORTH en la JVM, por lo que la igualdad referencial coincide con la igualdad de valor.
En un switch
Los enums y switch están hechos el uno para el otro:
switch (d) {
case NORTH -> System.out.println("up");
case SOUTH -> System.out.println("down");
case EAST, WEST -> System.out.println("sideways");
}Observa el NORTH sin prefijo en lugar de Direction.NORTH — dentro de un switch sobre un enum, el compilador conoce el tipo. Si añades una nueva constante y olvidas manejarla en una expresión switch, obtendrás un error de compilación sobre no-exhaustividad, que es exactamente la red de seguridad que quieres.
Campos, constructores y métodos
Un enum puede llevar datos y comportamiento. Cada constante se construye con argumentos, y el cuerpo del enum puede definir métodos normales:
public enum Planet {
MERCURY(3.303e+23, 2.4397e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6);
private final double massKg;
private final double radiusM;
Planet(double massKg, double radiusM) {
this.massKg = massKg;
this.radiusM = radiusM;
}
public double surfaceGravity() {
final double G = 6.67300E-11;
return G * massKg / (radiusM * radiusM);
}
}Dos reglas para recordar:
- La lista de constantes va primero en el cuerpo, separada del resto por un punto y coma.
- El constructor es implícitamente privado — los enums no pueden instanciarse desde fuera, que es precisamente el objetivo.
Métodos incorporados
Todo enum obtiene algunos métodos de forma gratuita:
name()devuelve el nombre declarado de la constante como unString.ordinal()devuelve su posición de base cero en la declaración. Ocasionalmente útil; evita persistirlo porque reordenar las constantes cambia silenciosamente el significado.values()devuelve un array de todas las constantes en el orden de declaración — ideal para buclesfor (Direction d : Direction.values()). Construye un nuevo array en cada llamada, así que guárdalo en una variable local si iteras en un bucle crítico para el rendimiento.valueOf(String)busca una constante por su nombre exacto (sensible a mayúsculas) y lanzaIllegalArgumentExceptionsi no hay coincidencia.
Como valueOf lanza excepción con entrada desconocida, protégelo cuando la cadena provenga de fuera de tu código — entrada de usuario, un archivo, una carga de red:
Direction d = Direction.valueOf("EAST"); // EAST
try {
Direction.valueOf("UP"); // not a declared constant
} catch (IllegalArgumentException e) {
System.out.println("no such constant"); // no such constant
}Comportamiento por constante
A veces una constante necesita comportarse de manera diferente a las demás. Puedes sobrescribir métodos por constante con un cuerpo anónimo:
public enum Operation {
PLUS { public int apply(int a, int b) { return a + b; } },
MINUS { public int apply(int a, int b) { return a - b; } },
TIMES { public int apply(int a, int b) { return a * b; } };
public abstract int apply(int a, int b);
}Cada constante se convierte en una pequeña subclase anónima de Operation que implementa apply. La sensación de patrón de estrategia viene incluida.
Implementar interfaces
Los enums pueden implementar interfaces — simplemente no pueden extender otras clases (extienden implícitamente java.lang.Enum):
public enum Day implements Runnable {
MONDAY, TUESDAY;
public void run() { System.out.println("today is " + name()); }
}Esta es una forma limpia de conectar una familia fija de estrategias a código que espera cualquier Runnable.
EnumSet y EnumMap
Cuando necesitas un Set o un Map con clave de enum, prefiere EnumSet y EnumMap sobre HashSet/HashMap. Ambos están respaldados por un vector de bits o un array plano del tamaño del enum, lo que evita el hashing por completo — las búsquedas son un solo índice de array, y un EnumSet de un enum pequeño cabe en un solo long:
EnumSet<Direction> horizontal = EnumSet.of(Direction.EAST, Direction.WEST);
EnumSet<Direction> all = EnumSet.allOf(Direction.class); // every constant
EnumSet<Direction> none = EnumSet.noneOf(Direction.class); // empty, ready to fill
EnumMap<Direction, String> labels = new EnumMap<>(Direction.class);
labels.put(Direction.NORTH, "up");La iteración sobre un EnumSet o EnumMap sigue el orden de declaración, lo que hace que su salida sea determinista — otra razón para preferirlos sobre las colecciones basadas en hash.
Un ejemplo completo
Qué sigue
Los enums fijan un conjunto de instancias. El siguiente capítulo introduce una forma diferente de clase restringida — records, diseñados para portadores de datos inmutables simples. Continúa en Java records.