W3docs

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 uma String.
  • 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ços for (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ça IllegalArgumentException se 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

java— editable, runs on the server

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.

Prática

Prática
Qual é o principal motivo para usar um enum em vez de um conjunto de constantes int?
Qual é o principal motivo para usar um enum em vez de um conjunto de constantes int?
Was this page helpful?