Chapter 35: Enums

No Comments

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

Section 35.1: 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();
MutableExample.A.increment();
MutableExample.A.print();
MutableExample.B.print();
// Outputs 0
// Outputs 1 — we’ve changed a field// 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

Section 35.2: 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.

Section 35.3: 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.

Section 35.4: 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
}
}

Section 35.5: 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.

Section 35.6: 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).

Section 35.7: 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.

Section 35.8: 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.

Section 35.9: 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 equalingfive-hundredth  of  a  United  States  dollar
*/
NICKEL(5), 
/**
The dime is a ten-cent coin refers toone 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;
}
}

Section 35.10: 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());
System.out.println(john.getGender());
System.out.println(jane.getGender());
// Male
// Male
// Female

Section 35.11: 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.

Section 35.12: 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);
printEnum(DefaultValues.VALUE_TWO);
// VALUE_ONE
// 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.

Section 35.13: 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”);
}
}
}

Section 35.14: 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;

Section 35.15: 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

Section 35.16: 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

System.out.println(Fruit.BANANA.toString()); //  “BANANA” System.out.println(Fruit.GRAPE_FRUIT.toString());   //  “GRAPE_FRUIT”
By default:
System.out.println(Fruit.BANANA.toString()); // “Banana” System.out.println(Fruit.GRAPE_FRUIT.toString());  //  “Grape  Fruit”
Example of being overridden

Section 35.17: 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

About us and this blog

We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

Request a free quote

We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

Subscribe to our newsletter!

More from our blog

See all posts
No Comments

Recent Posts