Introduction to Java Enums

Introduction

In this post, we will quickly discuss features and use cases of Java enums.Java enum were introduced in Java 5. It is a special Java type that holds a fixed set of constant values. Not only constants, but enums may also contain different methods, variables and different constructors for different constants defined in the enum.

Instead of using constant variables, we can use enums for more code-readability. They also provide type safety by restricting separate type input parameters in a method. In this tutorial, we learn how to create enums in Java, different use cases of Java enums, EnumSet and EnumMap. Each explanation includes example Java code and JUnit Test cases.

1. Java Enums Definition

For defining an enum type in Java, we need to use “enum” keyword. Let me show you with a simple example :

public enum DIGITS {
 ZERO,
 ONE,
 TWO,
 THREE,
 FOUR,
 FIVE,
 SIX,
 SEVEN,
 EIGHT,
 NINE
}

It defines an enum typeDIGITS”. Note that all values of an enum are constants and that is the reason we are using uppercase letters in the above example. You can refer to any of the constants in the above enum like below :

DIGITS digits = DIGITS.TWO;

“digits” is of type “DIGITS”. So, it can take any of the 10 constants we have defined above.

1.1. Java Enums Definition

We can use constructors, methods, private fields and variables in enums. It helps us to extend its functionality. The constructor executes separately for each enum constant during class loading time. So, we can define any variables with a different value for each enum constant. We cannot invoke the constructor directly. Let me show you with an example below :

public enum Digit {
 ONE(1) {
   @Override
   public boolean isEven() {
    return false;
   }
  },
  TWO(2) {
   @Override
   public boolean isEven() {
    return true;
   }
  },
  THREE(3) {
   @Override
   public boolean isEven() {
    return false;
   }
  },
  FOUR(4) {
   @Override
   public boolean isEven() {
    return true;
   }
  };

 private int currentValue;

 public boolean isEven() {
  return false;
 }

 Digit(int digit) {
  this.currentValue = digit;
 }
}

//Main.java:

 public class Main {

  public Digit digit;

  public void setDigit(Digit d) {
   this.digit = d;
  }

  public boolean isEven() {
   return digit.isEven();
  }
 }

Test class for the above “Main” class – MainTest.java :

import org.junit.Test;
import static org.junit.Assert.*;

public class MainTest {
 @Test
 public void testDigits() {
  Main main = new Main();
  main.setDigit(Digit.ONE);
  assertFalse(main.isEven());

  main.setDigit(Digit.FOUR);
  assertTrue(main.isEven());
 }
}

There are few important pointed to keep in mind.

  • As you can see, we have defined one different class “Digit” for the enum. If you want, you can use the enum inside the Main class directly.
  • In this example above, we have defined only four constants: ONE, TWO, THREE and FOUR, you can add more similarly.
  • The constructor is setting the value of currentValue. For each constant, this value will be different for the enum. For example, for THREE, it will be 3, for TWO it will be 2 etc.
  • – Each constant value overrides the method isEven and returns true or false accordingly.

2. Compare Two Enums

For comparing two enums, we can either use “==“ or “equals” method.  Since only one instance of the enum constant exists in JVM at a specific time, we can use “==“ without any problem. “==“ is more preferable than “equals” method as it provides run-time and compile-time safety to the comparison. Let me show you with two small examples what it means :

2.1 Runtime Safety

public class Main {
 public static void main(String[] args) {
  Digit currentValue = null;
  if (currentValue.equals(Digit.FOUR)) {
   //empty if statement
  }

  if (currentValue == Digit.FOUR) {
   //empty if statement
  }
 }
}

The first “if” statement will throw one NullPointerException but the second “if” statement will work fine. So, if any of the comparing values for the “equals” method is “null”, it will throw NullPointerException.

2.2 Compile Time Safety

public class Main {
 public static void main(String[] args) {
  Digit currentValue = Digit.TWO;

  if (currentValue.equals(Digit.FOUR)) {
   //empty if statement
  }

  if (currentValue == Digit.FOUR) {
   //empty if statement
  }
 }
}

Here, both “if” statements are false but for the second statement, the compiler will flag incompatibility error. For the first one, i.e. the statement we are using “equals” method, the compiler will not detect anything.

3. Conditional Statements

Since Java enums are actually constants, we can compare one enum value with a different value of the same enum type. This comparison can be done using any conditional statement like “if-else“, “switch” etc.

3.1 Using if,else-if Statements

public class Main {
 public static void main(String[] args) {
  Digit currentValue = Digit.TWO;

  if (currentValue == Digit.ONE) {
   System.out.println("Current value is one");
  } else if (currentValue == Digit.TWO) {
   System.out.println("Current value is two");
  } else if (currentValue == Digit.THREE) {
   System.out.println("Current value is three");
  } else if (currentValue == Digit.FOUR) {
   System.out.println("Current value is four");
  }
 }
}

Above program will print one different message based on the value of “currentValue“.

3.1 Switch Statements

Similar to <em>if</em>,<em>else-if</em>, we can also use the switch statement with “enum“. If you have a lot of constant values inside an enum, a switch is preferred more.

public class Main {
 public static void main(String[] args) {
  Digit currentValue = Digit.TWO;

  switch (currentValue) {
   case ONE:
    System.out.println("Current value is one");
    break;
   case TWO:
    System.out.println("Current value is two");
    break;
   case THREE:
    System.out.println("Current value is three");
    break;
   case FOUR:
    System.out.println("Current value is four");
    break;
  }
 }
}

4. Iterating Over an Enum

Iterating over an enum is easy. Each enum has one static values() method that returns all enum types defined in it. For example :

public class Main {
 public static void main(String[] args) {
  for (Digit digit: Digit.values()) {
   System.out.println(digit);
  }
 }
}

Output

ONE
TWO
THREE
FOUR

All the enum constants defined inside the enum. Note that this is one of the main difference between constants and enums in java. We cannot print the names of constants like enums.

5. EnumSet

EnumSet is a specialized set implementation for enum types. All of the elements in an enum set come from a single enum type. It extends AbstractSet and implements Set interface in Java.

import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;

public class Number {
 public enum Digit {
  ONE,
  TWO,
  THREE,
  FOUR
 }

 public static EnumSet < Digit > evenList = EnumSet.of(Digit.TWO, Digit.FOUR);
 private Digit currentValue;

 public void setValue(Digit value) {
  this.currentValue = value;
 }

 public Digit getCurrentValue() {
  return this.currentValue;
 }

 public static List < Number > getAllEvenList(List < Number > inputList) {
  return inputList.stream().filter(
    (s) -> evenList.contains(s.getCurrentValue()))
   .collect(Collectors.toList());
 }
}

import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;

public class Number {
 public enum Digit {
  ONE,
  TWO,
  THREE,
  FOUR
 }

 public static EnumSet < Digit > evenList = EnumSet.of(Digit.TWO, Digit.FOUR);
 private Digit currentValue;

 public void setValue(Digit value) {
  this.currentValue = value;
 }

 public Digit getCurrentValue() {
  return this.currentValue;
 }

 public static List < Number > getAllEvenList(List < Number > inputList) {
  return inputList.stream().filter(
    (s) -> evenList.contains(s.getCurrentValue()))
   .collect(Collectors.toList());
 }
}

6. EnumMap

Similar to EnumSet, we have map interface for enumeration types known as EnumMap. <em>EnumMap</em> extends AbstractMap and implements Map Interface in Java. Example :

public class Number {
 public enum Digit {
  ONE,
  TWO,
  THREE,
  FOUR
 }

 public static void main(String args[]) {
  EnumMap < Digit, Integer > enumMap = new EnumMap < > (Digit.class);

  enumMap.put(Digit.ONE, 1);
  enumMap.put(Digit.TWO, 2);
  enumMap.put(Digit.THREE, 3);
  enumMap.put(Digit.FOUR, 4);

  System.out.println("EnumMap : " + enumMap);
  System.out.println("Value for TWO is " + enumMap.get(Digit.TWO));
 }
}

Output

EnumMap : {ONE=1, TWO=2, THREE=3, FOUR=4}
Value for TWO is 2

Summary

In this tutorial, we have learned how to create Java enums variables and how to use enums in Java. Instead of using constant variables, we can use enums for better readability and better coding practice.

Enum also offers type safety, i.e. you cannot pass any values to a method if the argument type for that method is a specific enum. For large enum classes, we can create a separate file without placing it in the same class.As always the source code for this article is available on our GitHub repository.