Olá Pessoal, tudo bom?
O tipo Enumeration (enum) não foi originalmente desenvolvido para a linguagem Java, pois já existia em diversas outras linguagens como C, C++ e C#. Apesar disso é um mecanismo muito importante que facilita a criação de constantes de uma forma mais organizada e reutilizável. Esse artigo irá retratar como utilizar o enum dentro da linguagem Java.
O que é um Enum em Java?
Definição básica: Enum em Java é uma palavra chave.
Definição avançada: Enum é uma especialização da linguagem para representar um número fixo de valores previamente conhecidos. Por exemplo, os nomes dos dias de uma semana, os nomes dos meses que compõem um ano, os nomes dos presidentes da república, etc. Essa especialização foi introduzida na linguagem Java a partir da versão 1.5 da JDK.
Formas de utilização
Uma das formas de utilização mais comum é a representação de um conjunto de informações já conhecido ou o estado de um determinado ponto de um projeto. Por exemplo, suponha que estados de algum item perante uma venda. Podemos dizer que os estados de um item são DISPONIVEL, RESERVADO, ADQUIRIDO, EM_TRANSPORTE, ENTREGUE.
Representação de Enums antes da versão 1.5 do Java
Vamos analisar como seria a representação dos estados de um item antes da versão 1.5 do Java:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class EstadoVendaItem { public static final int DISPONIVEL = 0; public static final int RESERVADO = 1; public static final int ADQUIRIDO = 2; public static final int EM_TRANSPORTE = 3; public static final int ENTREGUE = 4; } public class ItemVenda { private int estadoVenda;//Inserir o valor correspondente por exemplo: //estadoVenda = EstadoVendaItem.DISPONIVEL } |
No código fonte acima as representações dos estados são realizadas com constantes (public static final) de números inteiros. Dessa forma para cada estado há um número inteiro que o representa. Para atribuir esse estado a um item é utilizado uma variável do mesmo tipo da constante, por exemplo int. Existem alguns pontos limitantes que podem ser observados disso:
- Primeiro, não possui uma tipagem segura, ou seja, não é type-safe. Podemos atribuir um valor que não representa um estado. Por exemplo, atribuir a variável estadoVenda o valor de 15, sendo que esse valor não representa nenhum estado válido de venda.
- Segundo, o valor impresso por essa constante não é amigável ou fácil de ser entendido. Vamos lá, pra entender que o estado de um item é Entregue, é mais fácil ler o número 5 ou a string “Entregue”?
- Terceiro, o valor do estado sempre será um inteiro, se for necessário adicionar outras informações ao estado, como por exemplo, qual é o próximo estado de um processo, não é possível de ser realizado.
Enums a partir da versão 1.5 do Java
Para corrigir essas limitações citadas acima, foi criado o Enum. Ele é type-safe, pode prover nomes amigáveis para as “constantes” e pode conter outras informações além do próprio valor da constante.
A representação do código do exemplo anterior em Enum é a seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 |
public enum EstadoVendaItem { DISPONIVEL, RESERVADO, ADQUIRIDO, EM_TRANSPORTE, ENTREGUE; } public class ItemVenda { private EstadoVendaItem estadoVenda; //Inserir o valor correspondente: //estadoVenda = EstadoVendaItem.DISPONIVEL } |
Algumas diferenças entre os códigos:
- Primeiro, diferente da representação de uma Class, um Enum não começa com o prefixo básico (public class), mas com uma palavra chave própria enum (public enum nomeEnum).
- Segundo, em uma representação de enum não são aceitos modificadores padrões (public, protected, private). Isso se deve ao fato que todas as constantes em um enum são public static final.
- Terceiro, todos os enums em Java possuem um construtor. Esse construtor também é inserido automaticamente pela linguagem, caso não tenha sido descrito pelo desenvolvedor. MAS, diferente de uma classe que é um construtor sem argumentos, esse construtor do enum recebe 2 parametros, Enum(String name, int ordinal).
- O primeiro parâmetro, name, é a própria constante descrita, por exemplo DISPONIVEL.
- O segundo parâmetro, ordinal, é a posição que a constante aparece no enum a partir do 0, assim a constante ADQUIRIDO, seria 2, para obter esse valor existe um método chamado int getOrdinal().
- Quarto, não existe mais uma variável do tipo inteiro para receber o valor, mas sim uma variável do tipo EstadoVendaItem. E essa variável somente aceitará constantes que estejam descritas no Enum ou o valor null.
Com esses pontos, podemos melhorar a resposta da definição de Enum em Java: “Java Enum é um tipo, como uma classe ou interface, e pode ser utilizada para definir um conjunto de constantes enum. Todas essas constantes são public, static e final e uma vez criada, através de um construtor próprio, não é possível alterar o seu valor a não ser recompilando o código novamente.”
Lembrando novamente, o tipo Enum foi introduzido a JVM a partir da versão 1.5, assim se seu código é mais antigo, será necessário uma refatoração para uma versão 1.5 ou superior. Um aspecto muito importante é a fácil manutenção de um Enum, bastando adicionar as novas constantes a ele.
Para realizar uma comparação entre enums pode-se utilizar o operador “==”, que apesar de ser static final, ou seja, a constante aponta para um mesmo endereço de memória, não é recomendável, pois esse operador é utilizado para comparações entre tipos primitivos. Para objetos a melhor forma é utilizar o método equals() ou o compareTo() da interface Comparable, conforme exemplo do código abaixo:
1 2 3 4 5 |
public void imprimeTipoPeso(PesoMaximoBagagemEnum pesoMaxEnum){ if(PesoMaximoBagagemEnum.NACIONAL.equals(pesoMaxEnum)){ System.out.println("Bagagem Nacional. Peso: " + pesoMaxEnum.getPeso()); } } |
Quando existe mais de uma informação para realizar uma comparação, podemos utilizar o switch case. E esse é um aspecto bem interessante para a utilização das constantes dos enums. Dependendo da quantidade de informação que precisa ser processada o switch pode ajudar na organização do código, como no código abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 |
public void imprimeTipoPeso(PesoMaximoBagagemEnum pesoMaxEnum){ switch (pesoMaxEnum) { case MAO: System.out.println("Bagagem Mao. Peso: " + pesoMaxEnum.getPeso()); break; case NACIONAL: System.out.println("Bagagem Nacional. Peso: " + pesoMaxEnum.getPeso()); break; case INTERNACIONAL: System.out.println("Bagagem Internacional. Peso: " + pesoMaxEnum.getPeso()); } } |
Perceba que o parâmetro que contém o valor do parâmetro é passado para o switch como predicado e todas as condições do Enum são representadas pelas suas constantes. Muito prático e organizado.
Agregando valor ao Enum…
Como já mencionado, é possível inserir mais informações úteis dentro de um Enum. Assim vamos supor que fosse necessário criar um enum com os pesos máximos das bagagens de viagens aéreas com os valores MAO, 5 quilos, NACIONAL, 23 quilos, INTERNACIONAL, 32 quilos. Como ficaria a codificação desse enum?
1 2 3 4 5 |
public enum PesoMaximoBagagemEnum { MAO, NACIONAL, INTERNACIONAL; } |
Com o código acima, qual é o valor que será obtido com o código NACIONAL.getOrdinal()? 23? 1? No caso dessa codificação o valor seria 1. Mas como poderíamos mudar para retornar o valor 23? Para isso vamos criar um construtor que receba como argumento o peso máximo, esse construtor deverá ser private, único modificador de construtor aceito para enums. Além disso, vamos criar um atributo de nome peso e um método getPeso() para obter o valor desse atributo. Dessa forma o código do enum seria atualizado com o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public enum PesoMaximoBagagemEnum { MAO(5), NACIONAL(23), INTERNACIONAL(32); int peso; private PesoMaximoBagagemEnum(int peso){ this.peso = peso; } public int getPeso(){ return peso; } } |
É possível criar um método setPeso(), mas este não faz sentido, já que o valor é setado pelo construtor do enum. Perceba que o construtor é private, ou seja, não é possível instanciar novas constantes do enum via operador new. Todas as constantes são inicializadas quando ocorre a primeira chamada ao enum no código, durante a execução.
Outro exemplo é que possível inserir mais informações dentro de uma constante enum, e assim possuir diversas informações relacionadas facilmente. Voltando ao exemplo inicial de estados de uma venda, podemos necessitar que dentro da constante possua o valor do próximo estado em um caminho perfeito de uma venda, sem que nenhum problema ocorra. Dessa forma o enum pode ficar da seguinte forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public enum EstadoVendaItem { DISPONIVEL(RESERVADO), RESERVADO(ADQUIRIDO), ADQUIRIDO(EM_TRANSPORTE), EM_TRANSPORTE(ENTREGUE), ENTREGUE(null); private EstadoVendaItem proximoEstado; private EstadoVendaItem(EstadoVendaItem proximoEstado){ this.proximoEstado = proximoEstado; } public EstadoVendaItem getProximoEstado(){ return proximoEstado; } } |
Ou ainda inserindo muito mais informações:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
public enum EnderecoAeroportoEnum { END_AERO_BRASILIA("Brasilia", "BSB", "DF047", 1, "Aeroporto", "Lago Sul", "Brasilia", "DF", "Brasil"), END_AERO_CONFINS("Confins", "CNF", "MG010", 1, "Kilometro 39", "Confins", "Belo Horizonte", "MG", "Brasil"), END_AERO_CURITIBA("Curitiba", "CWB", "Av. Rocha Pombo", 1, "Aeroporto", "Aguas Belas", "Sao Jose dos Pinhais", "PR", "Brasil"), END_AERO_GUARULHOS("Guarulhos", "GRU", "Rod. Helio Smidt", 1, "Aeroporto", "Cumbica", "Guarulhos", "SP", "Brasil"), END_AERO_PORTO_ALEGRE("Porto Alegre", "POA", "Av. Severo Dulius", 1, "Aeroporto", "Centro", "Porto Alegre", "RS", "Brasil"), END_AERO_SANTOS_DUMONT("Santos Dumont", "SDU", "Praca Sen. Salgado Filho", 1, "Aeroporto", "Centro", "Rio de Janeiro", "RJ", "Brasil"); private String nome, codigo, rua, complemento, bairro, cidade, estado, pais; private int numero; private EnderecoAeroportoEnum(String nome, String codigo, String rua, int numero, String complemento, String bairro, String cidade, String estado, String pais) { this.nome = nome; this.codigo = codigo; this.rua = rua; this.numero = numero; this.complemento = complemento; this.bairro = bairro; this.cidade = cidade; this.estado = estado; this.pais = pais; } public String getBairro() { return bairro; } public String getCidade() { return cidade; } public String getCodigo() { return codigo; } public String getComplemento() { return complemento; } public String getEstado() { return estado; } public String getNome() { return nome; } public int getNumero() { return numero; } public String getPais() { return pais; } public String getRua() { return rua; } } |
Métodos gerados automaticamente pela JDK
Além do construtor especializado gerado automaticamente pela JDK, existe um método que retorna um array de todas as constantes contidas no enum. Esse método é o values(), o qual retorna um array estático (array[]) com todas as constantes. Ele é muito útil para fazer métodos de comparação dentro do Enum, como na busca por um determinado peso, conforme mostra o código abaixo:
1 2 3 4 5 6 7 8 |
public static PesoMaximoBagagemEnum getBy(int peso){ for (PesoMaximoBagagemEnum e : PesoMaximoBagagemEnum.values()) { if(e.getPeso() == peso){ return e; } } return null; } |
Dois pontos aqui se fazem necessários. O primeiro é que o método se encontra dentro da classe PesoMaximoBagagemEnum, sendo static, pois quando precisar utilizar esse método se torna mais simples, por exemplo, PesoMaximoBagagemEnum.getBy(5); O segundo ponto é que a ordem das constantes que aparecem na iteração do for é a mesma da declaração do enum.
PS: Caso você não conheça o for que apareceu acima ele é o for each, que também foi inserido na versão 1.5 da JDK. Mais detalhes sobre esse for veja esse artigo.
finally{
Esse artigo teve a proposta de apresentar o mundo os enums. Caso existam duvidas ou sugestões de outras formas de utilização de enum, favor enviar seus comentários abaixo ou por email.
Obrigado e até o próximo post!
Java duvidas says
Muito Obrigado pelo exemplo!
Tenho uma pergunta…
Aqui
public enum EnderecoAeroportoEnum {
END_AERO_BRASILIA(“Brasilia”, “BSB”, “DF047”, 1, “Aeroporto”, “Lago Sul”, “Brasilia”, “DF”, “Brasil”),
END_AERO_CONFINS(“Confins”, “CNF”, “MG010”, 1, “Kilometro 39”, “Confins”, “Belo Horizonte”, “MG”, “Brasil”),
END_AERO_CURITIBA(“Curitiba”, “CWB”, “Av. Rocha Pombo”, 1, “Aeroporto”, “Aguas Belas”, “Sao Jose dos Pinhais”, “PR”, “Brasil”),
END_AERO_GUARULHOS(“Guarulhos”, “GRU”, “Rod. Helio Smidt”, 1, “Aeroporto”, “Cumbica”, “Guarulhos”, “SP”, “Brasil”),
END_AERO_PORTO_ALEGRE(“Porto Alegre”, “POA”, “Av. Severo Dulius”, 1, “Aeroporto”, “Centro”, “Porto Alegre”, “RS”, “Brasil”),
END_AERO_SANTOS_DUMONT(“Santos Dumont”, “SDU”, “Praca Sen. Salgado Filho”, 1, “Aeroporto”, “Centro”, “Rio de Janeiro”, “RJ”, “Brasil”);
private String nome, codigo, rua, complemento, bairro, cidade, estado, pais;
private int numero;
Quem é o int numero?
Mauda says
Olá, tudo bem?
Não entendi muito bem a pergunta, mas vou responder o que entendi, qualquer coisa manda nova pergunta.
numero é um atributo que representa o numero do endereço.
Se você observar no construtor verá que existe um parâmetro numero, que está na posição 4. Assim se você observar nas constantes verá que existe um 1 em praticamente todos as constantes, porque normalmente os aeroportos ocupam todo o endereço, não necessitando ter numeros.
Poderíamos ter um caso de endereço sem número? Sim poderíamos. Aí deveria ser mudado o tipo do atributo de int para Integer.
Caso o número tivesse letras, como existem algumas casas em que o terreno é dividido para abrigar 2 residências, aí teríamos que substituir o int por uma String.
Acredito que seja isso.
Novamente duvidas a disposição!
Obrigado!