Java LanguageEnums

Introduction

Java enums (declared using the enum keyword) are shorthand syntax for sizable quantities of constants of a single class.

Syntax

  • [public/protected/private] enum Enum_name { // Declare a new enum.
  • ENUM_CONSTANT_1[, ENUM_CONSTANT_2...]; // Declare the enum constants. This must be the first line inside of the enum, and should be separated by commas, with a semicolon at the end.
  • ENUM_CONSTANT_1(param)[, ENUM_CONSTANT_2(param)...]; // Declare enum constants with parameters. The parameter types must match the constructor.
  • ENUM_CONSTANT_1 {...}[, ENUM_CONSTANT_2 {...}...]; // Declare enum constants with overridden methods. This must be done if the enum contains abstract methods; all such methods must be implemented.
  • ENUM_CONSTANT.name() // Returns a String with the name of the enum constant.
  • ENUM_CONSTANT.ordinal() // Returns the ordinal of this enumeration constant, its position in its enum declaration, where the initial constant is assigned an ordinal of zero.
  • Enum_name.values() // Returns a new array (of type Enum_name[]) containing every constant of that enum everytime it is called.
  • Enum_name.valueOf("ENUM_CONSTANT") // The inverse of ENUM_CONSTANT.name() -- returns the enum constant with the given name.
  • Enum.valueOf(Enum_name.class, "ENUM_CONSTANT") // A synonym of the previous one: The inverse of ENUM_CONSTANT.name() -- returns the enum constant with the given name.

Remarks

Restrictions

Enums always extend java.lang.Enum, so it is impossible for an enum to extend a class. However, they can implement many interfaces.

Tips & Tricks

Because of their specialized representation, there are more efficient maps and sets that can be used with enums as their keys. These will often run quicker than their non-specialized counterparts.

Declaring and using a basic enum

Enum can be considered to be syntax sugar for a sealed class that is instantiated only a number of times known at compile-time to define a set of constants.

A simple enum to list the different seasons would be declared as follows:

public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

While the enum constants don't necessarily need to be in all-caps, it is Java convention that names of constants are entirely uppercase, with words separated by underscores.


You can declare an Enum in its own file:

/**
 * This enum is declared in the Season.java file.
*/
public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

But you can also declare it inside another class:

 public class Day {

    private Season season;

    public String getSeason() {
        return season.name();
    }

    public void setSeason(String season) {
        this.season = Season.valueOf(season);
    }

    /**
     * This enum is declared inside the Day.java file and 
     * cannot be accessed outside because it's declared as private.
     */
    private enum Season {
        WINTER,
        SPRING,
        SUMMER,
        FALL
    }

}

Finally, you cannot declare an Enum inside a method body or constructor:

public class Day {

    /**
     * Constructor
    */
    public Day() {
        // Illegal. Compilation error
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }
    }

    public void aSimpleMethod() {
        // Legal. You can declare a primitive (or an Object) inside a method. Compile!
        int primitiveInt = 42;

        // Illegal. Compilation error.
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }

        Season season = Season.SPRING;
    }
    
}

Duplicate enum constants are not allowed:

public enum Season {
    WINTER,
    WINTER, //Compile Time Error : Duplicate Constants
    SPRING,
    SUMMER,
    FALL
} 

Every constant of enum is public, static and final by default. As every constant is static, they can be accessed directly using the enum name.

Enum constants can be passed around as method parameters:

public static void display(Season s) {
    System.out.println(s.name());  // name() is a built-in method that gets the exact name of the enum constant
}

display(Season.WINTER);  // Prints out "WINTER"

You can get an array of the enum constants using the values() method. The values are guaranteed to be in declaration order in the returned array:

Season[] seasons = Season.values();

Note: this method allocates a new array of values each time it is called.


To iterate over the enum constants:

public static void enumIterate() {
    for (Season s : Season.values()) {
        System.out.println(s.name());
    }
}

You can use enums in a switch statement:

public static void enumSwitchExample(Season s) {
    switch(s) {
        case WINTER:
            System.out.println("It's pretty cold");
            break;
        case SPRING:
            System.out.println("It's warming up");
            break;
        case SUMMER:
            System.out.println("It's pretty hot");
            break;
        case FALL:
            System.out.println("It's cooling down");
            break;
    }
}

You can also compare enum constants using ==:

Season.FALL == Season.WINTER    // false
Season.SPRING == Season.SPRING  // true

Another way to compare enum constants is by using equals() as below, which is considered bad practice as you can easily fall into pitfalls as follows:

Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error

Furthermore, although the set of instances in the enum cannot be changed at run-time, the instances themselves are not inherently immutable because like any other class, an enum can contain mutable fields as is demonstrated below.

public enum MutableExample {
    A,
    B;

    private int count = 0;

    public void increment() {
        count++;
    }

    public void print() {
        System.out.println("The count of " + name() + " is " + count);
    }
}

// Usage:
MutableExample.A.print();       // Outputs 0
MutableExample.A.increment();
MutableExample.A.print();       // Outputs 1 -- we've changed a field   
MutableExample.B.print();       // Outputs 0 -- another instance remains unchanged

However, a good practice is to make enum instances immutable, i.e. when they either don't have any additional fields or all such fields are marked as final and are immutable themselves. This will ensure that for a lifetime of the application an enum won't leak any memory and that it is safe to use its instances across all threads.


Enums implicitly implement Serializable and Comparable because the Enum class does:

public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable

Enums with constructors

An enum cannot have a public constructor; however, private constructors are acceptable (constructors for enums are package-private by default):

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25); // usual names for US coins
    // note that the above parentheses and the constructor arguments match
    private int value;

    Coin(int value) { 
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

int p = Coin.NICKEL.getValue(); // the int value will be 5

It is recommended that you keep all fields private and provide getter methods, as there are a finite number of instances for an enum.


If you were to implement an Enum as a class instead, it would look like this:

public class Coin<T extends Coin<T>> implements Comparable<T>, Serializable{
    public static final Coin PENNY = new Coin(1);
    public static final Coin NICKEL = new Coin(5);
    public static final Coin DIME = new Coin(10);
    public static final Coin QUARTER = new Coin(25);

    private int value;

    private Coin(int value){
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

int p = Coin.NICKEL.getValue(); // the int value will be 5

Enum constants are technically mutable, so a setter could be added to change the internal structure of an enum constant. However, this is considered very bad practice and should be avoided.

Best practice is to make Enum fields immutable, with final:

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value){ 
        this.value = value;
    }

    ...

}

You may define multiple constructors in the same enum. When you do, the arguments you pass in your enum declaration decide which constructor is called:

public enum Coin {
    PENNY(1, true), NICKEL(5, false), DIME(10), QUARTER(25);

    private final int value;
    private final boolean isCopperColored;

    Coin(int value){
        this(value, false);
    }

    Coin(int value, boolean isCopperColored){ 
        this.value = value;
        this.isCopperColored = isCopperColored;
    }

    ...

}

Note: All non-primitive enum fields should implement Serializable because the Enum class does.

Using methods and static blocks

An enum can contain a method, just like any class. To see how this works, we'll declare an enum like this:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;
}

Let's have a method that returns the enum in the opposite direction:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction getOpposite(){
        switch (this){
            case NORTH:
                return SOUTH;               
            case SOUTH:
                return NORTH;                
            case WEST:
                return EAST; 
            case EAST:
                return WEST;  
            default: //This will never happen
                return null;
        }
    }
}

This can be improved further through the use of fields and static initializer blocks:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;
    
    private Direction opposite;
    
    public Direction getOpposite(){
        return opposite;
    }
    
    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        WEST.opposite = EAST;
        EAST.opposite = WEST;
    }
}

In this example, the opposite direction is stored in a private instance field opposite, which is statically initialized the first time a Direction is used. In this particular case (because NORTH references SOUTH and conversely), we cannot use Enums with constructors here (Constructors NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST) would be more elegant and would allow opposite to be declared final, but would be self-referential and therefore are not allowed).

Implements Interface

This is an enum that is also a callable function that tests String inputs against precompiled regular expression patterns.

import java.util.function.Predicate;
import java.util.regex.Pattern;

enum RegEx implements Predicate<String> {
    UPPER("[A-Z]+"), LOWER("[a-z]+"), NUMERIC("[+-]?[0-9]+");

    private final Pattern pattern;

    private RegEx(final String pattern) {
        this.pattern = Pattern.compile(pattern);
    }

    @Override 
    public boolean test(final String input) {
        return this.pattern.matcher(input).matches();
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(RegEx.UPPER.test("ABC"));
        System.out.println(RegEx.LOWER.test("abc"));
        System.out.println(RegEx.NUMERIC.test("+111"));
    }
}

Each member of the enum can also implement the method:

import java.util.function.Predicate;

enum Acceptor implements Predicate<String> {
    NULL {
        @Override
        public boolean test(String s) { return s == null; }
    },
    EMPTY {
        @Override
        public boolean test(String s) { return s.equals(""); }
    },
    NULL_OR_EMPTY {
        @Override
        public boolean test(String s) { return NULL.test(s) || EMPTY.test(s); }
    };
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Acceptor.NULL.test(null));  // true
        System.out.println(Acceptor.EMPTY.test(""));   // true
        System.out.println(Acceptor.NULL_OR_EMPTY.test(" ")); // false
    }
}

Enum Polymorphism Pattern

When a method need to accept an "extensible" set of enum values, the programmer can apply polymorphism like on a normal class by creating an interface which will be used anywere where the enums shall be used:

public interface ExtensibleEnum {
    String name();
}

This way, any enum tagged by (implementing) the interface can be used as a parameter, allowing the programmer to create a variable amount of enums that will be accepted by the method. This can be useful, for example, in APIs where there is a default (unmodifiable) enum and the user of these APIs want to "extend" the enum with more values.

A set of default enum values can be defined as follows:

public enum DefaultValues implements ExtensibleEnum {
    VALUE_ONE, VALUE_TWO;
}

Additional values can then be defined like this:

public enum ExtendedValues implements ExtensibleEnum {
    VALUE_THREE, VALUE_FOUR;
}

Sample which shows how to use the enums - note how printEnum() accepts values from both enum types:

private void printEnum(ExtensibleEnum val) {
    System.out.println(val.name());
}  

printEnum(DefaultValues.VALUE_ONE);    // VALUE_ONE
printEnum(DefaultValues.VALUE_TWO);    // VALUE_TWO
printEnum(ExtendedValues.VALUE_THREE); // VALUE_THREE
printEnum(ExtendedValues.VALUE_FOUR);  // VALUE_FOUR

Note: This pattern does not prevent you from redefining enum values, which are already defined in one enum, in another enum. These enum values would be different instances then. Also, it is not possible to use switch-on-enum since all we have is the interface, not the real enum.

Enums with Abstract Methods

Enums can define abstract methods, which each enum member is required to implement.

enum Action {
    DODGE {
        public boolean execute(Player player) {
            return player.isAttacking();
        }
    },
    ATTACK {
        public boolean execute(Player player) {
            return player.hasWeapon();
        }
    },
    JUMP {
        public boolean execute(Player player) {
            return player.getCoordinates().equals(new Coordinates(0, 0));
        }
    };

    public abstract boolean execute(Player player);
}

This allows for each enum member to define its own behaviour for a given operation, without having to switch on types in a method in the top-level definition.

Note that this pattern is a short form of what is typically achieved using polymorphism and/or implementing interfaces.

Documenting enums

Not always the enum name is clear enough to be understood. To document an enum, use standard javadoc:

/**
 * United States coins
 */
public enum Coins {
    
    /**
     * One-cent coin, commonly known as a penny, 
     * is a unit of currency equaling one-hundredth 
     * of a United States dollar
     */
    PENNY(1),

    /**
     * A nickel is a five-cent coin equaling 
     * five-hundredth of a United States dollar
     */        
    NICKEL(5),

    /**
     * The dime is a ten-cent coin refers to 
     * one tenth of a United States dollar
     */        
    DIME(10),

    /**
     * The quarter is a US coin worth 25 cents, 
     * one-fourth of a United States dollar
     */        
    QUARTER(25);

    private int value;

    Coins(int value){ 
        this.value = value;
    }

    public int getValue(){
        return value;
    }
}

Getting the values of an enum

Each enum class contains an implicit static method named values(). This method returns an array containing all values of that enum. You can use this method to iterate over the values. It is important to note however that this method returns a new array every time it is called.

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
    
    /**
    * Print out all the values in this enum.
    */
    public static void printAllDays() {
        for(Day day : Day.values()) {
            System.out.println(day.name());
        }
    }
}

If you need a Set you can use EnumSet.allOf(Day.class) as well.

Enum as a bounded type parameter

When writing a class with generics in java, it is possible to ensure that the type parameter is an enum. Since all enums extend the Enum class, the following syntax may be used.

public class Holder<T extends Enum<T>> {
    public final T value;

    public Holder(T init) {
        this.value = init;
    }
}

In this example, the type T must be an enum.

Get enum constant by name

Say we have an enum DayOfWeek:

enum DayOfWeek {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}

An enum is compiled with a built-in static valueOf() method which can be used to lookup a constant by its name:

String dayName = DayOfWeek.SUNDAY.name();
assert dayName.equals("SUNDAY");

DayOfWeek day = DayOfWeek.valueOf(dayName);
assert day == DayOfWeek.SUNDAY;

This is also possible using a dynamic enum type:

Class<DayOfWeek> enumType = DayOfWeek.class;
DayOfWeek day = Enum.valueOf(enumType, "SUNDAY");
assert day == DayOfWeek.SUNDAY;

Both of these valueOf() methods will throw an IllegalArgumentException if the specified enum does not have a constant with a matching name.

The Guava library provides a helper method Enums.getIfPresent() that returns a Guava Optional to eliminate explicit exception handling:

DayOfWeek defaultDay = DayOfWeek.SUNDAY;
DayOfWeek day = Enums.valueOf(DayOfWeek.class, "INVALID").or(defaultDay);
assert day == DayOfWeek.SUNDAY;

Implement Singleton pattern with a single-element enum

Enum constants are instantiated when an enum is referenced for the first time. Therefore, that allows to implement Singleton software design pattern with a single-element enum.

public enum Attendant {

    INSTANCE;

    private Attendant() {
        // perform some initialization routine
    }

    public void sayHello() {
        System.out.println("Hello!");
    }
}


public class Main {

    public static void main(String... args) {
        Attendant.INSTANCE.sayHello();// instantiated at this point
    }
}

According to "Effective Java" book by Joshua Bloch, a single-element enum is the best way to implement a singleton. This approach has following advantages:

  • thread safety
  • guarantee of single instantiation
  • out-of-the-box serialization

And as shown in the section implements interface this singleton might also implement one or more interfaces.

Enum with properties (fields)

In case we want to use enum with more information and not just as constant values, and we want to be able to compare two enums.

Consider the following example:

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value){
        this.value = value;
    }

    public boolean isGreaterThan(Coin other){
        return this.value > other.value;
    }

}

Here we defined an Enum called Coin which represent its value. With the method isGreaterThan we can compare two enums:

Coin penny = Coin.PENNY;
Coin dime = Coin.DIME;

System.out.println(penny.isGreaterThan(dime)); // prints: false
System.out.println(dime.isGreaterThan(penny)); // prints: true

Convert enum to String

Sometimes you want to convert your enum to a String, there are two ways to do that.

Assume we have:

public enum Fruit {
    APPLE, ORANGE, STRAWBERRY, BANANA, LEMON, GRAPE_FRUIT;
}

So how do we convert something like Fruit.APPLE to "APPLE"?


Convert using name()

name() is an internal method in enum that returns the String representation of the enum, the return String represents exactly how the enum value was defined.

For example:

System.out.println(Fruit.BANANA.name());      // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.name()); // "GRAPE_FRUIT"

Convert using toString()

toString() is, by default, overridden to have the same behavior as name()

However, toString() is likely overridden by developers to make it print a more user friendly String

Don't use toString() if you want to do checking in your code, name() is much more stable for that. Only use toString() when you are going to output the value to logs or stdout or something

By default:

System.out.println(Fruit.BANANA.toString());      // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "GRAPE_FRUIT"

Example of being overridden

System.out.println(Fruit.BANANA.toString());      // "Banana"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "Grape Fruit"

Enum constant specific body

In an enum it is possible to define a specific behavior for a particular constant of the enum which overrides the default behavior of the enum, this technique is known as constant specific body.

Suppose three piano students - John, Ben and Luke - are defined in an enum named PianoClass, as follows:

    enum PianoClass {
    JOHN, BEN, LUKE;
        public String getSex() {
            return "Male";
        }
        public String getLevel() {
            return "Beginner";
        }
    }

And one day two other students arrive - Rita and Tom - with a sex (Female) and level (Intermediate) that do not match the previous ones:

    enum PianoClass2 {
    JOHN, BEN, LUKE, RITA, TOM;
        public String getSex() {
            return "Male"; // issue, Rita is a female
        }
        public String getLevel() {
            return "Beginner"; // issue, Tom is an intermediate student
        }
    }

so that simply adding the new students to the constant declaration, as follows, is not correct:

PianoClass2 tom = PianoClass2.TOM;
PianoClass2 rita = PianoClass2.RITA;
System.out.println(tom.getLevel()); // prints Beginner -> wrong Tom's not a beginner
System.out.println(rita.getSex()); // prints Male -> wrong Rita's not a male

It's possible to define a specific behavior for each of the constant, Rita and Tom, which overrides the PianoClass2 default behavior as follows:

enum PianoClass3 {
    JOHN, BEN, LUKE,
    RITA {
        @Override
        public String getSex() {
            return "Female";
        }
    },
    TOM {
        @Override
        public String getLevel() {
            return "Intermediate";
        }
    };
    public String getSex() {
        return "Male";
    }
    public String getLevel() {
        return "Beginner";
    }
}

and now Tom's level and Rita's sex are as they should be:

PianoClass3 tom = PianoClass3.TOM;
PianoClass3 rita = PianoClass3.RITA;
System.out.println(tom.getLevel()); // prints Intermediate
System.out.println(rita.getSex()); // prints Female

Another way to define content specific body is by using constructor, for instance:

enum Friend {
    MAT("Male"),
    JOHN("Male"),
    JANE("Female");
    
    private String gender;

    Friend(String gender) {
        this.gender = gender;
    }

    public String getGender() {
        return this.gender;
    }
}

and usage:

Friend mat = Friend.MAT;
Friend john = Friend.JOHN;
Friend jane = Friend.JANE;
System.out.println(mat.getGender());     // Male
System.out.println(john.getGender());    // Male
System.out.println(jane.getGender());    // Female

Zero instance enum

enum Util {
    /* No instances */;

    public static int clamp(int min, int max, int i) {
        return Math.min(Math.max(i, min), max);
    }

    // other utility methods...
}

Just as enum can be used for singletons (1 instance classes), it can be used for utility classes (0 instance classes). Just make sure to terminate the (empty) list of enum constants with a ;.

See the question Zero instance enum vs private constructors for preventing instantiation for a discussion on pro's and con's compared to private constructors.

Enums with static fields

If your enum class is required to have static fields, keep in mind they are created after the enum values themselves. That means, the following code will result in a NullPointerException:

enum Example {
    ONE(1), TWO(2);

    static Map<String, Integer> integers = new HashMap<>();

    private Example(int value) {
        integers.put(this.name(), value);
    }
}

A possible way to fix this:

enum Example {
    ONE(1), TWO(2);

    static Map<String, Integer> integers;

    private Example(int value) {
        putValue(this.name(), value);
    }

    private static void putValue(String name, int value) {
        if (integers == null)
            integers = new HashMap<>();
        integers.put(name, value);
    }
}

Do not initialize the static field:

enum Example {
    ONE(1), TWO(2);

    // after initialisisation integers is null!!
    static Map<String, Integer> integers = null;

    private Example(int value) {
        putValue(this.name(), value);
    }

    private static void putValue(String name, int value) {
        if (integers == null)
            integers = new HashMap<>();
        integers.put(name, value);
    }
    // !!this may lead to null poiner exception!!
    public int getValue(){
        return (Example.integers.get(this.name()));
    }
}

initialisisation:

  • create the enum values
    • as side effect putValue() called that initializes integers
  • the static values are set
    • integers = null; // is executed after the enums so the content of integers is lost

Compare and Contains for Enum values

Enums contains only constants and can be compared directly with ==. So, only reference check is needed, no need to use .equals method. Moreover, if .equals used incorrectly, may raise the NullPointerException while that's not the case with == check.

enum Day {
    GOOD, AVERAGE, WORST;
}

public class Test {

    public static void main(String[] args) {
        Day day = null;

        if (day.equals(Day.GOOD)) {//NullPointerException!
            System.out.println("Good Day!");
        }

        if (day == Day.GOOD) {//Always use == to compare enum
            System.out.println("Good Day!");
        }

    }
}

To group, complement, range the enum values we have EnumSet class which contains different methods.

  • EnumSet#range : To get subset of enum by range defined by two endpoints

  • EnumSet#of : Set of specific enums without any range. Multiple overloaded of methods are there.

  • EnumSet#complementOf : Set of enum which is complement of enum values provided in method parameter

    enum Page {
       A1, A2, A3, A4, A5, A6, A7, A8, A9, A10
    }
    
    public class Test {
    
      public static void main(String[] args) {
          EnumSet<Page> range = EnumSet.range(Page.A1, Page.A5);
    
          if (range.contains(Page.A4)) {
              System.out.println("Range contains A4");
          }
    
          EnumSet<Page> of = EnumSet.of(Page.A1, Page.A5, Page.A3);
    
          if (of.contains(Page.A1)) {
              System.out.println("Of contains A1");
          }
      }
    }