Menu

Enums em Java: um conjunto fixo de constantes nomeadas

O que é um enum em Java, como declará-lo, adicionar campos e métodos, usá-lo em um switch e por que um enum é melhor do que um monte de constantes int ou String.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Um conjunto fixo de valores nomeados

Alguns valores só fazem sentido como um de uma lista pequena e conhecida: os dias da semana, os naipes de um baralho, os estados em que um pedido pode estar. Você poderia modelá-los com códigos int (0 para pendente, 1 para enviado) ou com strings ("PENDING", "SHIPPED"), mas nada impede que quem chama passe 7 ou "PNEDING". Um enum fecha esse buraco — o próprio tipo só aceita os valores que você declarou.

Day é um tipo totalmente novo. Uma variável do tipo Day pode conter exatamente uma dessas sete constantes (ou null) e nada mais. O compilador rejeita Day d = "WEDNESDAY"; ou Day d = 2;. Essa garantia é justamente o objetivo.

Cada constante (Day.MONDAY, e assim por diante) é uma única instância compartilhada, criada uma só vez. Como existe apenas um MONDAY, você compara enums com == em vez de equals — eles são o mesmo objeto.

Usando switch sobre um enum

Enums combinam naturalmente com switch. Você nem precisa qualificar cada constante com o nome do tipo dentro do switch:

Dentro do switch, escreva case SATURDAY, não case Day.SATURDAY — o Java infere o tipo. A grande vantagem em relação a usar switch sobre uma string ou int é que, se você adicionar uma nova constante mais tarde, o seu IDE e as verificações de exaustividade podem apontar cada switch que esqueceu de tratá-la.

Percorrendo todas as constantes

Todo enum recebe automaticamente um método estático values() que retorna todas as suas constantes na ordem de declaração, além de um ordinal() que dá a posição de cada constante começando em zero:

name() dá o identificador da constante como uma String, e values() é perfeito para montar menus ou iterar sobre opções. Um cuidado: não armazene o ordinal() em nenhum lugar persistente. Se alguém reordenar as constantes depois, os números mudam e os seus dados salvos quebram. Trate ordinal() como um detalhe de implementação, não como um identificador estável.

Enums são classes de verdade: campos e métodos

É aqui que os enums de Java vão além dos enums de inteiros nomeados de outras linguagens. Cada constante pode carregar dados, passados por um construtor, e o enum pode ter métodos. Você lista primeiro as constantes, dá a cada uma os seus argumentos de construtor e, depois de um ponto e vírgula, declara os campos, o construtor e os métodos.

Repare na estrutura: as constantes vêm primeiro e terminam com um ponto e vírgula, e então segue o restante da classe. O construtor é implicitamente private — você nunca pode escrever new Planet(...), porque as únicas instâncias permitidas são as declaradas no topo. Os campos final tornam cada constante imutável, que é exatamente o que você quer para singletons compartilhados.

De uma string e de volta

Para transformar uma string na constante correspondente, use o valueOf gerado automaticamente:

valueOf faz a correspondência do nome da constante de forma exata, incluindo maiúsculas e minúsculas, e lança IllegalArgumentException se não houver correspondência. Essa é a armadilha comum: "shipped" não corresponde a SHIPPED. Ao processar entrada do usuário ou dados externos, normalize primeiro o caso (input.toUpperCase()) e envolva a chamada em um try/catch, ou você vai quebrar no primeiro valor inválido.

Comportamento por constante

Às vezes cada constante precisa se comportar de forma diferente, não apenas guardar dados diferentes. Você pode dar ao enum um método abstrato e fazer cada constante fornecer a sua própria implementação em um pequeno corpo:

Isso é às vezes chamado de padrão de "método específico de constante". Ele substitui um switch enorme sobre a constante por comportamento anexado diretamente a cada uma — adicione uma nova operação e o compilador te obriga a definir o seu apply, então você não pode esquecer nenhum caso.

Quando usar um enum

Use um enum sempre que um valor for, naturalmente, um de um conjunto pequeno, fixo e conhecido em tempo de compilação:

  • Estados em um fluxo de trabalho (PENDING, SHIPPED, DELIVERED).
  • Categorias, modos ou tipos (READ, WRITE, EXECUTE).
  • Qualquer lugar em que você tenha sido tentado a definir um conjunto de constantes public static final int — o enum lhe dá os mesmos valores nomeados mais segurança de tipo, um toString legível e suporte a switch de graça.

Não use um enum para um conjunto aberto ou determinado em tempo de execução (nomes de usuário, uma lista de países obtida de um banco de dados). Enums são fixados em tempo de compilação; se o conjunto muda enquanto o programa roda, o que você quer é uma coleção comum.

Próximo: Generics

Você já viu values() retornando um Planet[] e, em páginas anteriores, o uso de List<Shape> — essa sintaxe <...> são os generics, a maneira de Java escrever uma classe ou método que funciona para muitos tipos mantendo total segurança de tipo. A seguir, vamos detalhar como List<String> e Map<K, V> realmente funcionam e como escrever os seus próprios tipos genéricos.

Perguntas frequentes

O que é um enum em Java?

Um enum é um tipo especial cujo valor só pode ser um de um conjunto fixo e nomeado de constantes, como Day.MONDAY ou Status.ACTIVE. Cada constante é uma única instância do enum, já pronta. Enums oferecem segurança de tipo: um método que recebe um Day só pode receber um dia real, nunca uma string digitada errada nem um int fora do intervalo.

Um enum em Java pode ter campos e métodos?

Sim. Um enum é uma classe completa. Você pode passar argumentos para o construtor de cada constante, armazená-los em campos private final e adicionar métodos que os utilizem. Por exemplo, MERCURY(3.3e23, 2.4e6) passa a massa e o raio para o construtor do enum, e um método surfaceGravity() pode calcular o resultado a partir desses campos.

Qual é a diferença entre values() e valueOf() em um enum Java?

values() retorna um array com todas as constantes do enum, na ordem de declaração — útil para percorrer cada opção. valueOf("NAME") faz o contrário: procura a constante cujo nome corresponde exatamente à string e lança IllegalArgumentException se nenhuma corresponder. Os dois são gerados automaticamente pelo compilador.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR