Java Enums

Todays topic is Java Enums. Here is a simple Java Enum definition. Three enum values are defined here, but the amount is unlimited.

SimpleEnum

public enum SimpleEnum {
   VALUE1, VALUE2, VALUE3;
}
Title - Java Enums

Java Enums

Here is a next sample code. Enumerators can have both methods and fields just as normal classes.

ComplexEnum

public enum ComplexEnum {
   VALUE;

   private int customPrivateField = 9;
   public int customPublicField;

   public void customMethod() {
       System.out.println("This is a custom enum method!");
   }

   public int getCustomPrivateField() {
       return customPrivateField;
   }

   @Override
   public String toString() {
       return "Overriden toString: " + super.toString() + "("
               + customPrivateField + ")";
   }
}

Enumerators can have as many constructors as needed. The constructors are always private and cannot be invoked even by reflection. The constructors are used in values definitions and only there. What is done with the parameters is defined by the developer. They can be used as normal constructor parameters.

In languages like C/C++/C# enums can have integer values assigned.

enum EnumName { VALUE1 = 10, VALUE2 = 20, VALUE3 = 30 };

In fact these enums are treated there as constants and can be cast into int value. In Java you cannot cast an enum to a primitive nor to any other class. But you can simulate assigning a value to it by using a proper constructor. Constructor can accept any kind of parameters and these can be stored in enum’s fields. Enumerators CANNOT have generic types.

EnumWithConstructors

public enum EnumWithConstructors {
   VALUE1(1), VALUE2, VALUE3(1, "test");

   /**
    * An empty constructor. Here used to instantiate VALUE2.
    */
   private EnumWithConstructors() {
   }

   /**
    * Constructor with one argument. Used to instantiate VALUE1.
    */
   private EnumWithConstructors(int a) {
   }

   /**
    * Constructor with two arguments. Used to instantiate VALUE3.
    */
   private EnumWithConstructors(int a, String b) {
   }
}

Enums can be used as a perfect singletons :) Because Java Virtual Machine will do most of the job for us:

  • first invoke of Singleton.INSTANCE will cause an instance to be initialized
  • there will NEVER be another instance of this enum
  • it can be used as a normal class

To turn a class into a singleton many more steps must be taken. The constructor need to be declared private. It will need to be initialized only once in a method that will return an instance of a singleton (a need to write a static access method). And in Java there should be a way to prevent developers from creating another instance using reflection.
So the following enum is a MUCH better way to create a singleton, isn’t it? ;)

Singleton

public enum Singleton {
   INSTANCE;
}

Sample usage – Basic Enums Operation

This method presents basic enums usage.

private static void presentBasicEnumOperations() throws Exception {
   System.out.println("Basic operations on enumerators.");
       
   //declare enum variable with set up value
   SimpleEnum simpleEnum1 = SimpleEnum.VALUE1;
   SimpleEnum simpleEnum2 = SimpleEnum.VALUE2;
   SimpleEnum simpleEnum3 = SimpleEnum.VALUE3;
       
   System.out.println("Enum behaves like a normal instance of a class; they can be printed ...");
   System.out.println(simpleEnum1);
   System.out.println(simpleEnum2.toString());
       
   System.out.println("... they can be compared using equals...");
   System.out.println(simpleEnum1.equals(simpleEnum2));
   System.out.println(simpleEnum1.equals("string"));
   System.out.println(simpleEnum3.equals(simpleEnum3));
       
   System.out.println("... but they can also be compared safely using == operator among themselves (which should NOT be used for normal classes).");
   System.out.println(simpleEnum1 == simpleEnum2);
   //System.out.println(simpleEnum1 == "string");//this will cause compilation ERROR
   System.out.println(simpleEnum3 == simpleEnum3);
       
   System.out.println("They can be used in a switch statement.");
   switch(simpleEnum1) {
       case VALUE1:
           System.out.println("Enum: VALUE1");
           break;
       case VALUE2:
           System.out.println("Enum: VALUE2");
           break;
       case VALUE3:
           System.out.println("Enum: VALUE3");
           break;
       default:
           throw new Exception("Unknown enum value!");
   }
       
   System.out.println("They can be put into table, list or any other container.");
   SimpleEnum[] enumTable = new SimpleEnum[] {
       simpleEnum1, simpleEnum2, simpleEnum3, SimpleEnum.VALUE2
       };
   System.out.println(Arrays.toString(enumTable));
       
   List<SimpleEnum> enumList = new ArrayList<SimpleEnum>();//it can e used in generics too
   enumList.add(simpleEnum1);
   enumList.add(SimpleEnum.VALUE2);
   System.out.println(enumList);
}

While used it gives the following output:

Basic operations on enumerators.
Enum behaves like a normal instance of a class; they can be printed ...
VALUE1
VALUE2
... they can be compared using equals...
false
false
true
... but they can also be compared safely using == operator among themselves (which should NOT be used for normal classes).
false
true
They can be used in a switch statement.
Enum: VALUE1
They can be put into table, list or any other container.
[VALUE1, VALUE2, VALUE3, VALUE2]
[VALUE1, VALUE2]

Sample usage – Enum references

This method shows a way of getting the enum reference.

private static void gettingEnumsReferences() throws Exception {
   System.out.println("Getting an enum reference.");
   //enums are instantiated when they are loaded by classloader and further instantiation is pointless
   //this means that there are only as many instances of the enum as the amount of its declared values
       
   System.out.println("In the application we only reference enumerators.");
   SimpleEnum simpleEnum1 = SimpleEnum.VALUE1;
   SimpleEnum simpleEnum2 = SimpleEnum.VALUE2;
   SimpleEnum simpleEnum3 = SimpleEnum.VALUE3;
       
   System.out.println("Enums CANNOT be created using the new operator ...");
   //SimpleEnum error = new SimpleEnum();    <------ THIS WILL CAUSE COMPILATION ERROR
       
   System.out.println("... and using reflection will be of no use either.");
   try {
       SimpleEnum.class.newInstance();
   } catch(InstantiationException e) {
       System.out.println("ERROR: Although the compiler will allow the operation from try block, it will always FAIL: " + e.getLocalizedMessage());
   }
       
   System.out.println("Enum can be retreivied by name (but this is NOT instantiation).");
   SimpleEnum simpleEnum = SimpleEnum.valueOf("VALUE1");
   System.out.println(simpleEnum);
       
   System.out.println("But providing invalid name will cause an error.");
   try {
       SimpleEnum.valueOf("vALUE1");//take notice that this is case-sensitive !!!!!!
   } catch(IllegalArgumentException e) {
       System.out.println("ERROR: When invoking valueOf it is important to remember about the case-sensitivness.");
   }
       
   System.out.println("All available enums can be simply enlisted.");
   SimpleEnum[] enums = SimpleEnum.values();
   for(SimpleEnum e : enums) {
       System.out.println(e);
   }
       
   System.out.println("Enum can be retrieved using an enum class name and the proper value name.");
   SimpleEnum e = Enum.valueOf(SimpleEnum.class, "VALUE1");
   System.out.println(e);
}

The output of this method is as follows:

Getting an enum reference.
In the application we only reference enumerators.
Enums CANNOT be created using the new operator ...
... and using reflection will be of no use either.
ERROR: Although the compiler will allow the operation from try block, it will always FAIL: com.itcuties.java.enums.data.SimpleEnum
Enum can be retrieved by name (but this is NOT instantiation).
VALUE1
But providing invalid name will cause an error.
ERROR: When invoking valueOf it is important to remember about the case-sensitiveness.
All available enums can be simply enlisted.
VALUE1
VALUE2
VALUE3
Enum can be retrieved using an enum class name and the proper value name.
VALUE1

Sample usage – Behaving like classes

This method shows that an enum can be used like any other class instance. You can invoke methods and alter fields.

private static void enumsBehavingLikeClasses() throws Exception {
   System.out.println("Enumerators can behave like normal classes.");
   ComplexEnum complexEnum = ComplexEnum.VALUE;
       
   System.out.println("A custom method can be called.");
   complexEnum.customMethod();
       
   System.out.println("Custom toString will be called when printing the enum.");
   System.out.println(complexEnum);
       
   System.out.println("Fields can be accessed (the access scope is of course defined by the access modifier).");
   System.out.println(complexEnum.customPublicField);
       
   System.out.println("The fields can be altered just like in a normal class.");
   complexEnum.customPublicField = 89;
   System.out.println(complexEnum.customPublicField);
}

The output is:

Enumerators can behave like normal classes.
A custom method can be called.
This is a custom enum method!
Custom toString will be called when printing the enum.
Overriden toString: VALUE(9)
Fields can be accessed (the access scope is of course defined by the access modifier).
0
The fields can be altered just like in a normal class.
89

Download this sample code here.

This code is available on our GitHub repository as well.

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Java by Example App is available at Google Play Store NOW