Java Enums
Defina um conjunto fixo de constantes em Java com tipos enum, incluindo enums com campos, construtores e métodos.
Um enum é uma classe cujas instâncias formam um conjunto fixo de valores conhecidos em tempo de compilação. Dias da semana, cores de semáforo, status de pedido — qualquer situação em que os valores válidos sejam uma lista pequena e nomeada. Ao escrever enum Status { OPEN, CLOSED }, esses dois são os únicos valores de Status que jamais existirão, e o compilador avisará caso você tente inventar um terceiro.
Os enums substituem o antigo hábito de C de usar public static final int OPEN = 0;. Constantes inteiras não oferecem segurança de tipos — setStatus(7) compila — mas setStatus(Status status) aceita apenas um dos valores declarados.
Declarando um enum
A forma mais simples é apenas uma lista de nomes de constantes:
public enum Direction {
NORTH, EAST, SOUTH, WEST
}Use como qualquer outro tipo:
Direction d = Direction.NORTH;
if (d == Direction.NORTH) System.out.println("heading up");Cada constante é uma instância singleton de Direction. Comparar com == é correto e idiomático — há apenas um NORTH na JVM, então igualdade de referência equivale a igualdade de valor.
Em um switch
Enums e switch foram feitos um para o outro:
switch (d) {
case NORTH -> System.out.println("up");
case SOUTH -> System.out.println("down");
case EAST, WEST -> System.out.println("sideways");
}Note o NORTH simples em vez de Direction.NORTH — dentro de um switch sobre um enum, o compilador já conhece o tipo. Se você adicionar uma nova constante e esquecer de tratá-la numa expressão switch, obterá um erro de compilação sobre não-exaustividade, que é exatamente a proteção desejada.
Campos, construtores e métodos
Um enum pode carregar dados e comportamento. Cada constante é construída com argumentos, e o corpo do enum pode definir métodos normais:
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);
}
}Duas regras para lembrar:
- A lista de constantes vem primeiro no corpo, separada do restante por um ponto e vírgula.
- O construtor é implicitamente privado — enums não podem ser instanciados de fora, o que é exatamente o objetivo.
Métodos embutidos
Todo enum recebe alguns métodos gratuitamente:
name()retorna o nome declarado da constante como umaString.ordinal()retorna sua posição zero-based na declaração. Útil ocasionalmente; evite persistir esse valor porque reordenar as constantes altera o significado silenciosamente.values()retorna um array com todas as constantes na ordem de declaração — ótimo para laçosfor (Direction d : Direction.values()). Ele constrói um novo array a cada chamada, então armazene-o em uma variável local se iterar em um laço crítico.valueOf(String)busca uma constante pelo nome exato (diferencia maiúsculas de minúsculas) e lançaIllegalArgumentExceptionse não houver correspondência.
Como valueOf lança exceção para entradas desconhecidas, proteja-o quando a string vier de fora do seu código — entrada do usuário, um arquivo, uma carga de rede:
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
}Comportamento por constante
Às vezes uma constante precisa se comportar de forma diferente das outras. Você pode sobrescrever métodos por constante com um corpo 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 torna-se uma pequena subclasse anônima de Operation que implementa apply. O estilo do padrão strategy vem de graça.
Implementando interfaces
Enums podem implementar interfaces — apenas não podem estender outras classes (eles implicitamente estendem java.lang.Enum):
public enum Day implements Runnable {
MONDAY, TUESDAY;
public void run() { System.out.println("today is " + name()); }
}Essa é uma forma limpa de encaixar uma família fixa de estratégias em código que espera qualquer Runnable.
EnumSet e EnumMap
Quando você precisar de um Set ou Map com chave de enum, prefira EnumSet e EnumMap em vez de HashSet/HashMap. Ambos são implementados por um vetor de bits ou um array simples dimensionado ao enum, evitando completamente o hashing — as buscas são um único índice de array, e um EnumSet de um enum pequeno cabe em um único 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");A iteração sobre um EnumSet ou EnumMap segue a ordem de declaração, tornando a saída determinística — mais um motivo para preferi-los às coleções baseadas em hash.
Um exemplo completo
O que vem a seguir
Enums restringem um conjunto fixo de instâncias. O próximo capítulo apresenta um formato diferente de classe restrita — records, projetados para portadores de dados imutáveis simples. Continue em Java records.