Signup/Sign In
PUBLISHED ON: AUGUST 19, 2021

Java Enum

An Enum(short for enumeration) is a special data type in Java that contains a fixed set of constants. Enum is a special kind of class that extends the java.lang.Enum class. Enums allow us to know all the possible values for a field at the compile-time and make our code more readable. We can use them to avoid undesirable behavior due to invalid inputs. For example, an enum of directions can only have four possible values - north, south, east, and west. In this tutorial, we will learn more about enums in Java.

Creating a Simple Enum

  • An enumeration is created by specifying the constant values that it can have.
  • We use the enum keyword to create an enumeration in Java. All the enum constants must be written in capital letters(NORTH, not north).
  • All enum constants are static and final. Static allows us to access the constants by using the name of the enum.

Example

Let's create a simple enum that denotes the result of students in an exam. The student could have passed or failed the exam or could have been absent for the exam.

public enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

We can create a variable of the enum type by using one of the constants.

public class Demo
{
	public static void main(String[] args)
	{
		StudentResult result1 = StudentResult.ABSENT;
		StudentResult result2 = StudentResult.FAIL;
		StudentResult result3 = StudentResult.PASS;
		
		System.out.println(result1);
		System.out.println(result2);
		System.out.println(result3);
	}
}


ABSENT
FAIL
PASS

Using Enum with If-Else Statements

Enums are very frequently used with conditional statements, as they can only have a fixed constant value. The code below demonstrates this.

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{
		StudentResult result = StudentResult.FAIL;
		
		if(result == StudentResult.ABSENT)
			System.out.println("The student was absent for the exam.");
		
		else if(result == StudentResult.PASS)
			System.out.println("The student passed the exam.");
		
		else if(result == StudentResult.FAIL)
			System.out.println("The student failed the exam.");
	}
}


The student failed the exam.

Using Enums with Switch Statements

If the number of constants is more, then switch-case statements are a better choice than if-else statements.

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{
		StudentResult result = StudentResult.FAIL;
		
		switch(result)
		{
			case ABSENT : System.out.println("The Student was absent for the exam.");
			break;
			
			case PASS : System.out.println("The Student passed the exam.");
			break;
			
			case FAIL : System.out.println("The Student failed the exam.");
			break;
		}
	}
}


The Student failed the exam.

Iterating an Enum

We can get an array of all enum constants by using the values() method. We can then traverse this array and fetch individual constants. We can also fetch the array index of each constant by using the ordinal() method.

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{
		StudentResult[] resultArr = StudentResult.values();
		
		for(StudentResult sr : resultArr)
		{
			System.out.println(sr + " at index " + sr.ordinal());
		}
	}
}


PASS at index 0
FAIL at index 1
ABSENT at index 2

toString() Method of Enums

All enum types get a toString() method that returns the string value of the enum constants. This allows us to perform common string operations on the returned value.

In the code below, we are first fetching each constant and converting it to a string. Next, we will convert all of them to lowercase and print them.

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{	
		for(StudentResult sr : StudentResult.values())
		{
			String resultStr = sr.toString();
			System.out.println("Uppercase: " + resultStr);
			System.out.println("Lowercase: " + resultStr.toLowerCase());
			System.out.println();
		}
	}
}


Uppercase: PASS
Lowercase: pass

Uppercase: FAIL
Lowercase: fail

Uppercase: ABSENT
Lowercase: absent

Enum from Strings

In the previous section, we learned how to convert an enum constant to a string. We can also create an enum type variable from a string value. The valueOf() method is used for this conversion.

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{	
		String resultStr = "FAIL";
		StudentResult result = StudentResult.valueOf(resultStr);
		System.out.print("Enum from String: " + result);
	}
}


Enum from String: FAIL

If the string is invalid or doesn't represent any enum constant, then an IllegalArgumentException is thrown.

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{	
		String resultStr = "PRESENT";//Invalid enum constant
		StudentResult result = StudentResult.valueOf(resultStr);
	}
}


Exception in thread "main" java.lang.IllegalArgumentException: No enum constant StudentResult.PRESENT
at java.base/java.lang.Enum.valueOf(Enum.java:273)
at StudentResult.valueOf(Demo.java:1)
at Demo.main(Demo.java:13)

Enum Inside Classes

We can also define enum types inside a class and use them as data members for the class. In the code below, we have a Student class with a name field. Let's define the StudentResult enum inside this class. We will also this enum type for a data member of the class. Let's also define a few methods that use the enum data member.

package saddas;

public class Student
{
	String name;
	StudentResult result;
	
	//Defining an enum type
	enum StudentResult
	{
		PASS,
		FAIL,
		ABSENT;
	}
    
	//Constructor
	Student(String s, StudentResult sr)
	{
		name = s;
		result = sr;
	}
    
	//enum if-else method
	public void printResult()
	{
		if(this.result == StudentResult.ABSENT)
			System.out.println(this.name + " was absent for the exam.");
		
		else if(this.result == StudentResult.PASS)
			System.out.println(this.name + " passed the exam.");
		
		else
			System.out.println(this.name + " failed the exam.");
	}
	
	//enum method
	public boolean wasAbsent()
	{
		if(this.result == StudentResult.ABSENT)
			return true;
		else
			return false;
	}
	
	//main method
	public static void main(String[] args)
	{
		Student s1 = new Student("Justin", StudentResult.ABSENT);
		Student s2 = new Student("Jessica", StudentResult.PASS);
		
		s1.printResult();
		s2.printResult();
		
		System.out.println("Student s1 was absent: " + s1.wasAbsent());
	}
}


Justin was absent for the exam.
Jessica passed the exam.
Student s1 was absent: true

EnumSet

An EnumSet is a special type of set designed to store enum constants in an efficient format. The EnumSet uses Bit Vector Representation for storing the enum constants. EnumSet can perform all the regular set operations. It is always recommended to prefer EnumSets over regular Sets when working with enum types. We can use the of() method to create an EnumSet of selected constants. Or we can use the allOf() method to create an EnumSet of all the constants of the set.

import java.util.EnumSet;

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{
		EnumSet resultSet1 = EnumSet.of(StudentResult.FAIL, StudentResult.PASS);
		EnumSet resultSet2 = EnumSet.allOf(StudentResult.class);
		
		System.out.println("Enum Set-1: " + resultSet1);
		System.out.print("Enum Set-2: " + resultSet2);
	}
}


Enum Set-1: [PASS, FAIL]
Enum Set-2: [PASS, FAIL, ABSENT]

EnumMaps

EnumMaps are special map implementations designed for enum types. EnumMaps stores key-value pairs, where the key is always an enum constant, and the value can be of any type. Just like an EnumSet, the EnumMaps are better and more efficient than normal HashMaps for storing enums. We can perform all the normal map operations on the EnumMap.

import java.util.EnumMap;
import java.util.Map;

enum StudentResult
{
	PASS,
	FAIL,
	ABSENT;
}

public class Demo
{
	public static void main(String[] args)
	{
		EnumMap<StudentResult, String> resultMap = new EnumMap<>(StudentResult.class);
		resultMap.put(StudentResult.PASS, "Student Passed the exam");
		resultMap.put(StudentResult.FAIL, "Student Failed the exam");
		resultMap.put(StudentResult.ABSENT, "Student was absent for the exam");
		
		for(Map.Entry<StudentResult, String> e : resultMap.entrySet())
			System.out.println(e.getKey() + " --> " + e.getValue());
	}
}


PASS --> Student Passed the exam
FAIL --> Student Failed the exam
ABSENT --> Student was absent for the exam

Enum Fields

We can add a field or data member to the enum type. This field will be associated with each constant. We can initialize this enum field for each constant by using a constructor.

For example, in the code below, we have added a percent field of String type to the enum. We have also written a constructor for this field. All the enum constants have called this constructor with different parameters.

Note that the constructor of an enum is always private. We cannot use any other modifier. Private is implicitly added if no access modifier is specified.

enum StudentResult
{	
	PASS("Above 35%"),//Constructor called with value "Above 35%"
	FAIL("Below 35%"),//Constructor called with value "Below 35%"
	ABSENT("N/A");//Constructor called with value "N/A"
	
	
	String percent; //Enum Field
	
	private StudentResult(String percent)//Private constructor
	{
		this.percent = percent;
	}
}

public class Demo
{
	public static void main(String[] args)
	{
		for(StudentResult s : StudentResult.values())
			System.out.println(s + " -> " + s.percent);
	}
}


PASS -> Above 35%
FAIL -> Below 35%
ABSENT -> N/A

Enum Methods

Enums can contain concrete and abstract methods. For abstract methods, each instance or constant of the enum must implement it. Let's take a look at an example for both of these scenarios.

Concrete Method

Let's add a print() method to our enum. This will print the enum constant and the percent field of the constant.

enum StudentResult
{
	PASS("Above 35%"),//Constructor called with value "Above 35%"
	FAIL("Below 35%"),//Constructor called with value "Below 35%"
	ABSENT("N/A");//Constructor called with value "N/A"
	
	
	String percent; //Enum Field
	
	private StudentResult(String percent)//Private constructor
	{
		this.percent = percent;
	}
	
	//Enum Method
	public void print()
	{
		System.out.println(this + " --> " + this.percent);
	}
}


public class Demo
{
	public static void main(String[] args)
	{
		for(StudentResult s : StudentResult.values())
			s.print();
	}
}


PASS --> Above 35%
FAIL --> Below 35%
ABSENT --> N/A

Abstract Method

Let's make the print() method abstract. Now, each constant should override it.

enum StudentResult
{
	PASS("Above 35%"){
		//Override the abstract print method
		@Override 
		void print() {
			System.out.println("Pass(Above 35%)");
		}
	},
	FAIL("Below 35%"){
		//Override the abstract print method
		@Override 
		void print() {
			System.out.println("Fail(Below 35%)");
		}
	},
	ABSENT("N/A"){
		//Override the abstract print method
		@Override 
		void print() {
			System.out.println("Absent for the exam");
		}
	};
	
	String percent;//Enum field
	
	StudentResult(String percent)//private constructor
	{
		this.percent = percent;
	}
	
	//Abstract Enum Method
	abstract void print();
}


public class Demo
{
	public static void main(String[] args)
	{
		for(StudentResult s : StudentResult.values())
			s.print();
	}
}


Pass(Above 35%)
Fail(Below 35%)
Absent for the exam

Implementing an Interface

An enum type cannot extend other classes, as it implicitly extends the java.lang.Enum class. However, it can implement other interfaces. The following code demonstrates this.

interface DemoInterface
{
	void print();
}

enum StudentResult implements DemoInterface
{
	PASS("Above 35%"),//Constructor called with value "Above 35%"
	FAIL("Below 35%"),//Constructor called with value "Below 35%"
	ABSENT("N/A");//Constructor called with value "N/A"
	
	String percent;//Enum Field
	
	private StudentResult(String percent)//Private constructor
	{
		this.percent = percent;
	}
	
	//implementing the interface method
	@Override
	public void print()
	{
		System.out.println(this + " --> " + this.percent);
	}
}


public class Demo
{
	public static void main(String[] args)
	{
		for(StudentResult s : StudentResult.values())
			s.print();
	}
}


PASS --> Above 35%
FAIL --> Below 35%
ABSENT --> N/A

Summary

Enums are used to define a collection of constant values. The following points summarize the key concepts learned in this tutorial.

  • They are very similar to classes having final and static members.
  • An enum is internally implemented using a final class. Each enum constant is a static and final data member of the class.
  • The compiler internally adds the values(), valueOf(), and the ordinal() method to our enum.
  • An enum can also contain other fields and constructors to initialize these fields.
  • The constructor must always be private, and we cannot use the new keyword to create an instance of our enum.
  • Enums can also contain concrete and abstract methods. The enum instances must implement for the abstract methods.
  • Enums implicitly extend the java.lang.Enum class, and so cannot extend any other class. But they can implement other interfaces.
  • They increase type safety, as the compiler knows exactly what constants to expect with the enum type instances.


About the author:
I am a 3rd-year Computer Science Engineering student at Vellore Institute of Technology. I like to play around with new technologies and love to code.