Enum en Java

El tipo Enum fue introducido en Java 1.5 como un nuevo tipo cuyos campos consisten en un conjunto fijo de constantes. Por ejemplo, podemos crear direcciones como Enum en Java con campos fijos como EAST, WEST, NORTH y SOUTH.

Enum de Java

En este tutorial, aprenderemos cómo crear un Enum. También veremos los beneficios de usar enums en Java y las características de los tipos enum. También aprenderemos a usar Java Enum valueOf, enum values, EnumSet y EnumMap con ejemplos.

Ejemplo de Enum en Java

La palabra clave enum de Java se utiliza para crear un tipo de enum. Veamos un programa de ejemplo de enum de Java.

package com.journaldev.enums;

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

En el ejemplo anterior, ThreadStates es el enum con campos de constantes fijas START, RUNNING, WAITING y DEAD.

Enum de Java vs Constantes

Ahora veamos cómo enum de Java es mejor que los campos de constantes normales en las clases de Java. Creemos una clase de constantes similar en 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;
}

Ahora veamos cómo se usan tanto las enumeraciones como las constantes en un programa Java:

/**
* This method shows the benefit of using Enum over Constants
*/
private static void benefitsOfEnumOverConstants() {
	//Los valores de la enumeración son fijos
	simpleEnumExample(ThreadStates.START);
	simpleEnumExample(ThreadStates.WAITING);
	simpleEnumExample(ThreadStates.RUNNING);
	simpleEnumExample(ThreadStates.DEAD);
	simpleEnumExample(null);
		
	simpleConstantsExample(1);
	simpleConstantsExample(2);
	simpleConstantsExample(3);
	simpleConstantsExample(4);
	//podemos pasar cualquier constante entera
	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");
}

Si observamos el ejemplo anterior, tenemos dos riesgos al usar constantes que se resuelven con la enumeración.

  1. Podemos pasar cualquier constante entera al método simpleConstantsExample, pero solo podemos pasar valores fijos a simpleEnumExample, lo que proporciona seguridad de tipo.
  2. Podemos cambiar el valor de las constantes enteras en la clase ThreadStatesConstant, pero el programa anterior no lanzará ninguna excepción. Nuestro programa puede no funcionar como se espera, pero si cambiamos las constantes de la enumeración, obtendremos un error en tiempo de compilación que elimina cualquier posibilidad de problemas en tiempo de ejecución.

Métodos de Enum en Java

Ahora veamos más características de la enumeración en Java con un ejemplo.

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();
	//Los constructores de la enumeración siempre deben ser privados.
	private ThreadStatesEnum(int i){
		priority = i;
	}
	
	//La enumeración puede tener métodos
	public int getPriority(){
		return this.priority;
	}
	
	public void setPriority(int p){
		this.priority = p;
	}
	
	//La enumeración puede anular funciones
	@Override
	public String toString(){
		return "Default ThreadStatesConstructors implementation. Priority="+getPriority();
	}

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

Puntos Importantes sobre Enum en Java

A continuación se presentan algunos de los puntos importantes para las enumeraciones en Java.

  1. Todos los enum de Java implícitamente extienden la clase `java.lang.Enum`, que a su vez extiende la clase Object e implementa las interfaces `Serializable` y `Comparable`. Por lo tanto, no podemos extender ninguna clase en un enum. `
  2. ` Dado que enum es una palabra clave, no podemos finalizar el nombre del paquete con ella, por ejemplo, `com.journaldev.enum` no es un nombre de paquete válido. `
  3. ` Los enum pueden implementar `interfaces`. Como en el ejemplo de enum anterior, está implementando la interfaz `Closeable`. `
  4. ` Los constructores de enum siempre son privados. `
  5. ` No podemos crear una instancia de enum utilizando el operador new. `
  6. ` Podemos declarar `métodos abstractos en enum de Java`, entonces todos los campos de enum deben implementar el método abstracto. En el ejemplo anterior, `getDetail()` es el método abstracto y todos los campos de enum lo han implementado. `
  7. ` Podemos definir un método en enum y los campos de enum también pueden anularlo. Por ejemplo, el método `toString()` está definido en enum y el campo de enum START lo ha anulado. `
  8. ` Los campos enum de Java tienen espacio de nombres, podemos usar el campo enum solo con el nombre de la clase como `ThreadStates.START`. `
  9. ` Los enums se pueden utilizar en una `declaración switch`, lo veremos en acción en la parte posterior de este tutorial.
  10. Podemos extender un enum existente sin romper ninguna funcionalidad existente. Por ejemplo, podemos agregar un nuevo campo NUEVO en el enum ThreadStates sin afectar ninguna funcionalidad existente.
  11. Dado que los campos enum son constantes, la mejor práctica en Java es escribirlos en letras mayúsculas y usar guiones bajos para los espacios. Por ejemplo, ESTE, OESTE, DIRECCION_ESTE, etc.
  12. Las constantes enum son implícitamente estáticas y finales.
  13. Las constantes enum son finales, pero su variable aún puede cambiarse. Por ejemplo, podemos usar el método setPriority() para cambiar la prioridad de las constantes enum. Lo veremos en el siguiente ejemplo de uso.
  14. Dado que las constantes enum son finales, podemos compararlas de manera segura usando los métodos “==” e equals(). Ambos tendrán el mismo resultado.

Java EnumSet, EnumMap, valueOf()

Ahora que conocemos la mayoría de las características de Enum, veamos un ejemplo de programa de Enum en Java. Luego aprenderemos algunas características más de un enum.

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 otras características importantes de enum, veamos la salida del programa anterior.

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

Puntos importantes

  1. El método usingEnumMethods() muestra cómo crear un objeto de enumeración y cómo podemos usar sus métodos. También muestra el uso del método setPriority(int i) para cambiar la variable de la enumeración.
  2. usingEnumValueOf() muestra el uso de java.util.Enum valueOf(enumType, name) a través del cual podemos crear un objeto de enumeración a partir de una cadena. Lanza una IllegalArgumentException si el tipo de enumeración especificado no tiene una constante con el nombre especificado, o si el objeto de clase especificado no representa un tipo de enumeración. También lanza una NullPointerException si alguno de los argumentos es nulo.
  3. El método usingEnumValues() muestra el uso del método values() que devuelve un array conteniendo todos los valores de la enumeración en el orden en que se declaran. Tenga en cuenta que este método se genera automáticamente por el compilador de Java para cada enumeración. No encontrará la implementación de values() en la clase java.util.Enum.
  4. El método usingEnumInSwitch() muestra cómo usar constantes de enumeración en un caso de interruptor.
  5. El método usingEnumMap() muestra el uso de java.util.EnumMap, que se introdujo en el Framework de Colecciones de Java 1.5. EnumMap es una implementación de Map para usar con claves de tipo enumerado. Todas las claves en un mapa de enumeración deben provenir de un solo tipo de enumeración que se especifica, explícita o implícitamente, cuando se crea el mapa. No podemos usar nulo como clave para EnumMap y EnumMap no está sincronizado.
  6. usingEnumSet() método muestra el uso de java.util.EnumSet, que es una implementación de Set para utilizar con tipos enum. Todos los elementos en un conjunto enum deben provenir de un solo tipo enum que se especifica, explícita o implícitamente, cuando se crea el conjunto. EnumSet no está sincronizado y no se permiten elementos nulos. También proporciona algunos métodos útiles como copyOf(Collection<E> c), of(E first, E... rest) y complementOf(EnumSet<E> s).

Puedes revisar todos los ejemplos en nuestro Repositorio de GitHub.

Referencia: Documentación de Oracle

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