Enum em Java

O Enum foi introduzido no Java 1.5 como um novo tipo cujos campos consistem em um conjunto fixo de constantes. Por exemplo, podemos criar direções como Enum em Java com campos fixos como LESTE, OESTE, NORTE e SUL.

Enum Java

Neste tutorial, aprenderemos como criar um Enum. Também veremos os benefícios de usar enums em Java e as características dos tipos de enum. Também aprenderemos a usar valueOf do Java Enum, values do enum, EnumSet e EnumMap com exemplos.

Exemplo de Enum Java

A palavra-chave enum do Java é usada para criar um tipo de enum. Vamos dar uma olhada no programa de exemplo de enum do Java.

package com.journaldev.enums;

public enum ThreadStates {
	START,
	RUNNING,
	WAITING,
	DEAD;
}

No exemplo acima, ThreadStates é o enum com campos de constantes fixas START, RUNNING, WAITING e DEAD.

Enum Java vs Constantes

Agora vamos ver como o enum do Java é melhor do que os campos de constantes normais em classes Java. Vamos criar uma classe de constantes semelhante em java.

package com.journaldev.enums;

public class ThreadStatesConstant {
	public static final int START = 1;
	public static final int WAITING = 2;
	public static final int RUNNING = 3;
	public static final int DEAD = 4;
}

Agora vamos ver como tanto enum quanto constantes são usados em um programa Java:

/**
* This method shows the benefit of using Enum over Constants
*/
private static void benefitsOfEnumOverConstants() {
	//Os valores do enum são fixos
	simpleEnumExample(ThreadStates.START);
	simpleEnumExample(ThreadStates.WAITING);
	simpleEnumExample(ThreadStates.RUNNING);
	simpleEnumExample(ThreadStates.DEAD);
	simpleEnumExample(null);
		
	simpleConstantsExample(1);
	simpleConstantsExample(2);
	simpleConstantsExample(3);
	simpleConstantsExample(4);
	//Podemos passar qualquer constante int
	simpleConstantsExample(5);
}

private static void simpleEnumExample(ThreadStates th) {
	if(th == ThreadStates.START) System.out.println("Thread started");
	else if (th == ThreadStates.WAITING) System.out.println("Thread is waiting");
	else if (th == ThreadStates.RUNNING) System.out.println("Thread is running");
	else System.out.println("Thread is dead");
}
	
private static void simpleConstantsExample(int i) {
	if(i == ThreadStatesConstant.START) System.out.println("Thread started");
	else if (i == ThreadStatesConstant.WAITING) System.out.println("Thread is waiting");
	else if (i == ThreadStatesConstant.RUNNING) System.out.println("Thread is running");
	else System.out.println("Thread is dead");
}

Se olharmos o exemplo acima, temos dois riscos ao usar constantes que são resolvidos pelo enum.

  1. Podemos passar qualquer constante int para o método simpleConstantsExample, mas podemos passar apenas valores fixos para simpleEnumExample, então ele fornece segurança de tipo.
  2. Podemos alterar o valor das constantes int na classe ThreadStatesConstant, mas o programa acima não lançará nenhuma exceção. Nosso programa pode não funcionar como esperado, mas se alterarmos as constantes do enum, receberemos um erro de tempo de compilação que elimina qualquer possibilidade de problemas em tempo de execução.

Métodos Enum em Java

Agora vamos ver mais características do enum em Java com um exemplo.

package com.journaldev.enums;

import java.io.Closeable;
import java.io.IOException;

/**
 * This Enum example shows all the things we can do with Enum types
 *
 */
public enum ThreadStatesEnum implements Closeable{
	START(1){
		@Override
		public String toString(){
			return "START implementation. Priority="+getPriority();
		}

		@Override
		public String getDetail() {
			return "START";
		}
	},
	RUNNING(2){
		@Override
		public String getDetail() {
			return "RUNNING";
		}
	},
	WAITING(3){
		@Override
		public String getDetail() {
			return "WAITING";
		}
	},
	DEAD(4){
		@Override
		public String getDetail() {
			return "DEAD";
		}
	};
	
	private int priority;
	
	public abstract String getDetail();
	//Os construtores do enum devem sempre ser privados.
	private ThreadStatesEnum(int i){
		priority = i;
	}
	
	//O enum pode ter métodos
	public int getPriority(){
		return this.priority;
	}
	
	public void setPriority(int p){
		this.priority = p;
	}
	
	//O enum pode substituir funções
	@Override
	public String toString(){
		return "Default ThreadStatesConstructors implementation. Priority="+getPriority();
	}

	@Override
	public void close() throws IOException {
		System.out.println("Close of Enum");
	}
}

Pontos Importantes do Enum em Java

Abaixo estão alguns dos pontos importantes para Enums em Java.

  1. Todos os enum java implicitamente estendem a classe java.lang.Enum que estende a classe Object e implementa as interfaces Serializable e Comparable. Portanto, não podemos estender nenhuma classe no enum.
  2. Como enum é uma palavra-chave, não podemos terminar o nome do pacote com ela, por exemplo, com.journaldev.enum não é um nome de pacote válido.
  3. O Enum pode implementar interfaces. Como no exemplo de enum acima, está implementando a interface Closeable.
  4. Os construtores do Enum são sempre privados.
  5. Não podemos criar uma instância de enum usando o operador new.
  6. Podemos declarar métodos abstratos em enums java, então todos os campos do enum devem implementar o método abstrato. No exemplo acima, getDetail() é o método abstrato e todos os campos do enum o implementaram.
  7. Podemos definir um método no enum e os campos do enum podem sobrescrevê-lo também. Por exemplo, o método toString() é definido no enum e o campo do enum START o sobrescreveu.
  8. Os campos do enum Java têm um namespace, podemos usar o campo do enum apenas com o nome da classe, como ThreadStates.START
  9. Os enums podem ser usados em declarações switch, veremos isso em ação na parte posterior deste tutorial.
  10. Podemos estender uma enumeração existente sem quebrar qualquer funcionalidade existente. Por exemplo, podemos adicionar um novo campo NEW na enumeração ThreadStates sem afetar qualquer funcionalidade existente.
  11. Como os campos da enumeração são constantes, a melhor prática em Java é escrevê-los em letras maiúsculas e usar sublinhado para espaços. Por exemplo, EAST, WEST, EAST_DIRECTION, etc.
  12. As constantes da enumeração são implicitamente estáticas e finais
  13. As constantes da enumeração são finais, mas suas variáveis ainda podem ser alteradas. Por exemplo, podemos usar o método setPriority() para alterar a prioridade das constantes da enumeração. Veremos isso em uso no exemplo abaixo.
  14. Como as constantes da enumeração são finais, podemos compará-las com segurança usando os métodos “==” e equals(). Ambos terão o mesmo resultado.

Java EnumSet, EnumMap, valueOf()

Agora que conhecemos a maioria das características de uma enumeração, vamos dar uma olhada em um programa de exemplo em Java. Em seguida, aprenderemos mais algumas características de uma enumeração.

package com.journaldev.enums;

import java.io.IOException;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Set;

public class JavaEnumExamples {

	public static void main(String[] args) throws IOException {
				
		usingEnumMethods();
		
		usingEnumValueOf();
		
		usingEnumValues();
		
		usingEnumInSwitch(ThreadStatesEnum.START);
		usingEnumInSwitch(ThreadStatesEnum.DEAD);
		
		usingEnumMap();
		
		usingEnumSet();
		
	}

	private static void usingEnumSet() {
		EnumSet enumSet = EnumSet.allOf(ThreadStatesEnum.class);
		for(ThreadStatesEnum tsenum : enumSet){
			System.out.println("Using EnumSet, priority = "+tsenum.getPriority());
		}
	}

	private static void usingEnumMap() {
		EnumMap<ThreadStatesEnum, String> enumMap = new EnumMap<ThreadStatesEnum,String>(ThreadStatesEnum.class);
		enumMap.put(ThreadStatesEnum.START, "Thread is started");
		enumMap.put(ThreadStatesEnum.RUNNING, "Thread is running");
		enumMap.put(ThreadStatesEnum.WAITING, "Thread is waiting");
		enumMap.put(ThreadStatesEnum.DEAD, "Thread is dead");
		
		Set keySet = enumMap.keySet();
		for(ThreadStatesEnum key : keySet){
			System.out.println("key="+key.toString()+":: value="+enumMap.get(key));
		}
		
	}

	private static void usingEnumInSwitch(ThreadStatesEnum th) {
		switch (th){
		case START:
			System.out.println("START thread");
			break;
		case WAITING:
			System.out.println("WAITING thread");
			break;
		case RUNNING:
			System.out.println("RUNNING thread");
			break;
		case DEAD:
			System.out.println("DEAD thread");
		}
	}

	private static void usingEnumValues() {
		ThreadStatesEnum[] thArray = ThreadStatesEnum.values();
		
		for(ThreadStatesEnum th : thArray){
			System.out.println(th.toString() + "::priority="+th.getPriority());
		}
	}

	private static void usingEnumValueOf() {
		ThreadStatesEnum th = Enum.valueOf(ThreadStatesEnum.class, "START");
		System.out.println("th priority="+th.getPriority());
	}

	private static void usingEnumMethods() throws IOException {
		ThreadStatesEnum thc = ThreadStatesEnum.DEAD;
		System.out.println("priority is:"+thc.getPriority());
		
		thc = ThreadStatesEnum.DEAD;
		System.out.println("Using overriden method."+thc.toString());
		
		thc = ThreadStatesEnum.START;
		System.out.println("Using overriden method."+thc.toString());
		thc.setPriority(10);
		System.out.println("Enum Constant variable changed priority value="+thc.getPriority());
		thc.close();
	}

}

Antes de explicar outros recursos importantes de uma enumeração, vamos ver a saída do programa acima.

priority is:4
Using overriden method.Default ThreadStatesConstructors implementation. Priority=4
Using overriden method.START implementation. Priority=1
Enum Constant variable changed priority value=10
Close of Enum
th priority=10
START implementation. Priority=10::priority=10
Default ThreadStatesConstructors implementation. Priority=2::priority=2
Default ThreadStatesConstructors implementation. Priority=3::priority=3
Default ThreadStatesConstructors implementation. Priority=4::priority=4
START thread
DEAD thread
key=START:: value=Thread is started
key=RUNNING:: value=Thread is running
key=WAITING:: value=Thread is waiting
key=DEAD:: value=Thread is dead
Using EnumSet, priority = 10
Using EnumSet, priority = 2
Using EnumSet, priority = 3
Using EnumSet, priority = 4

Pontos importantes

  1. O método usingEnumMethods() mostra como criar um objeto enum e como podemos usar seus métodos. Também está demonstrando o uso do método setPriority(int i) para alterar a variável do enum.
  2. usingEnumValueOf() mostra o uso de java.util.Enum valueOf(enumType, name) através do qual podemos criar um objeto enum a partir de uma String. Ele lança IllegalArgumentException se o tipo de enum especificado não tiver uma constante com o nome especificado, ou o objeto de classe especificado não representar um tipo de enum. Ele também lança NullPointerException se algum dos argumentos for nulo.
  3. O método usingEnumValues() mostra o uso do método values() que retorna um array contendo todos os valores do enum na ordem em que são declarados. Note que este método é gerado automaticamente pelo compilador Java para cada enum. Você não encontrará a implementação de values() na classe java.util.Enum.
  4. O método usingEnumInSwitch() mostra como usar constantes enum em um caso switch.
  5. O método usingEnumMap() mostra o uso de java.util.EnumMap, que é introduzido no Framework de Coleções do Java 1.5. EnumMap é uma implementação de Map para uso com chaves do tipo enum. Todas as chaves em um enum map devem ser do mesmo tipo enum especificado, explicitamente ou implicitamente, quando o mapa é criado. Não podemos usar nulo como chave para EnumMap e EnumMap não é sincronizado.
  6. usingEnumSet() método mostra o uso de java.util.EnumSet, que é uma implementação de Set para uso com tipos enum. Todos os elementos em um conjunto enum devem vir de um único tipo enum que é especificado, explicitamente ou implicitamente, quando o conjunto é criado. EnumSet não é sincronizado e elementos nulos não são permitidos. Ele também fornece alguns métodos úteis como copyOf(Collection<E> c), of(E first, E... rest) e complementOf(EnumSet<E> s).

Você pode verificar todos os exemplos do nosso Repositório do GitHub.

Referência: Documento da Oracle

Source:
https://www.digitalocean.com/community/tutorials/java-enum