The Complete Java Enums Tutorial with Examples

This tutorial explains the fundamentals of Java enums with examples. It starts with defining enum types. Next it explains where enums can be defined – in a class file of their own, alongside another class definition, or as a member of another class. Next the values() and valueOf() static methods of enum are covered, along with the ordinal() method, with code examples to show the methods’ usage. Enum equality is then touched upon briefly along with benefits of using enums. After covering the basics of Java enums, the tutorial then moves on to explain enhanced enums with variables, methods and constructors with detailed code examples. It then covers the topic of specific method overriding for an enum constant, aka constant specific class body, with examples. Lastly, the tutorial shows how enums can be efficiently used to decide between multiple execution paths when using switch-case statements.

What are enums

Enums are types which represent a fixed set of related constants.

Let us break the above definition down into the terms used in it to make it simpler –

  • Fixed Set – Enums have a fixed number of values specified upfront when defining an enum type.
  • Related Constants – The fixed set of values are for a given enum type defined. Hence, these enum values are related by their common enum type.
  • Enums are types – Enums are types in themselves; they are in fact special types of classes.

Examples of Enums

  1. Departments in an OrganizationHUMAN RESOURCES, MARKETING, IT, OPERATIONS are all departments of an organization. Hence, for a Department enum the fixed set of enum values are the department names.
  2. Sizes of ShirtsSMALL, MEDIUM, LARGE, EXTRA_LARGE are all sizes which a shirt can take. Hence, for a ShirtSize enum the fixed set of enum values are the various shirt sizes.

Defining an Enum
Let us take the Department enum from the 1st example we saw above and start building upon it. To start with, defining a fixed set of constant values for departments as an enum is as simple as writing the following code –

Simplest enum definition
public enum Department {
  HR, OPERATIONS, LEGAL, MARKETING //; semi-colon is optional here
}
Important points to note in above enum definition

  • Department enum has four values – HR, OPERATIONS, LEGAL, MARKETING.
  • The 4 department constants can be accessed as Department.HR, Department.OPERATIONS and so on.(Note – The syntax to access enums can vary based on where enums are defined which will be covered shortly.)
  • Semi-colon(;) at the end of enum constants is optional unless you decide to add more to the enum in terms of variables, methods etc., which will be covered further down under the topic enhanced enums.
  • It is important to note at this stage that

Enums are special types of classes
All enum types are classes. When an enum type is compiled, then behind the scenes the compiler inserts a lot of boilerplate code which gives the enum type classes their ‘special’ nature. This boiler code provides features of a full blown class and object constants definitions based on just the enum definition. So, in effect the compiler is doing all the hard work involved in creating a type and its constants objects behind-the-scenes, and abstracting it all out as a simple enum type and constants definition. Thus, all a programmer needs to do is define a enum type and its constants, and the compiler does the rest automatically.

Let us now quickly take a look at all the features which the Java compiler provides to an enum type –

  • All enums implicitly extend java.lang.Enum<E>.
  • Methods name(), ordinal() and valueOf(), inherited from Enum<E>, are available on all enums.
  • Enum objects cannot be created explicitly except by using reflection.
  • Boilerplate code includes the definition of a fixed set of instance variables which are public static final objects corresponding to each of the enum constants defined for that type.
  • Static values() method is available on all enum types. When invoked on an enum type, values() method returns an array of all enum constants defined for that enum type.
  • toString() method, overridden automatically by the compiler for all enum constants, returns the name of the enum constant as a string by default.
  • Enums can be used in switch-case statements (explained with code example further down).

Enum Naming Convention
By convention, enum values are named in capitals and underscores(_). This is because enum values are constant values , and in Java constants are named in capitals and underscores.

Where to define enums
Similar to other type definitions in Java, enums can be defined in the following ways –

  1. Enums can be defined independently(as a top-level class)
    • In a file which contains only the enum definition
      Enum defined in a separate Java file
      //In file - Department.Java
      public enum Department {
        HR, OPERATIONS, LEGAL, MARKETING
      }
      
      //In file EnumTest.java
      public class EnumTest {
        public static void main(String args[]) {
          Department enumVar = Department.HR;
        }
      }
      
      Important points to note in above code

      • Department.java file contains only the Department enum definition.
      • Department enum can be defined with public or default access in this case.
      • An enum constant of Department type can be accessed using the syntax – <enum-name>.<constant-name>. For example, in the above program the enum constants of Department can be accessed as – Department.HR, Department.OPERATIONS, and so on.
      • In the class EnumTest, a variable of type Department is defined as enumVar, which is assigned the HR Department using syntax Department.HR.
    • enum definition can accompany another class definition in that class’ file
      Enum defined alongside another class in same file
      //In file Employee.java
      enum Department {
        HR, OPERATIONS, LEGAL, MARKETING
      }
      
      public class Employee {
        String name;
        Integer age;
        Double salary;
      }
      Important points to note in above code

      • Employee.java file contains Employee class definition along with Department enum definition.
      • Department enum can be defined with only default access in this case, as only a type which is named after the file name(Employee class in this case) can be public in Java.
      • An enum constant of Department type can be accessed using the syntax – <enum-name>.<constant-name>. This is same as that for previous enum definition in its own file, as both this enum and previous one are not defined as member of another class.
  2. Enums can be defined as members of a class aka ‘nested enum types’.
    Nested enum defined as member of a class
    //In file Employee.java
    public class Employee {
     enum Department {
        HR, OPERATIONS, LEGAL, MARKETING;
      }
      private String name;
      private Integer age;
    }
    //In file EnumTest.java
    public class EnumTest {
      public static void main(String args[]) {
        Employee.Department enumVar = Employee.Department.HR;
      }
    }
    Important points to observe in above code

    • Employee.java file contains Employee class definition.
    • Department enum is defined inside Employee class.
    • Department enum in this case can be defined with any desired access, (i.e. public, private, default), here.
    • Department enum defined above is a nested enum type as it is ‘nested’ inside another class. Nested enum types are implicitly static, and hence mentioning static in their definition is actually redundant.
    • An enum constant of static nested enum Department type can be accessed using the syntax – <enclosing-class-name>.<enum-name>.<constant-name>. For example, in the above program the enum constants of Department can be accessed as – Employee.Department.HR, Employee.Department.OPERATIONS, and so on.
    • In the class EnumTest.java, a variable of type Employee.Department is defined as enumVar, which is assigned the HR Department accessed using syntax Employee.Department.HR.

What exactly is an enum – logically!
Logically an enum is a set of fixed/constant instances of an enum ‘type’. So, a Department type above has 4 constant instances – HR, OPERATIONS, LEGAL, MARKETING. Now any variable defined in any class which is of type Department can have only one of these 4 constant values.

Using the static values() method of an enum
The static values() method is a very handy method as it is available on every enum type, and when invoked it returns an array of all enum constants of that enum type. Lets see a code example showing the use of values() method.

Example showing enum's values() method usage
public class EnumTest {
  public static void main(String args[]) {
    for(Department dept:Department.values()){
      System.out.println("Enum constant-> "+dept+" with ordinal value-> "+dept.ordinal());
    }
  }
}
 OUTPUT of the above code
Enum constant-> HR with ordinal value-> 0
Enum constant-> OPERATIONS with ordinal value-> 1
Enum constant-> LEGAL with ordinal value-> 2
Enum constant-> MARKETING with ordinal value-> 3
Explanation of the code

  • Example uses the enum Department which we defined in a file of its own.
  • Using a for loop, the constants in Department enum are iterated through. Each enum constant’s value and ordinal position is printed as it is encountered.
What is ordinal value of an enum constant What is ordinal value of an enum constant
Ordinal value of an enum constant, accessed using the syntax <enum-constant>.ordinal() is an int value equal to the enum constant’s ordinal position in enum declaration, starting from the value 0(zero).

Using the static valueOf() method of an enum
Static valueOf() method, which can be invoked on the enum type, takes a single String parameter which needs to be the name of any of the constants of the enum on which this method is invoked. It returns an enum constant object whose name matches the name value passed as parameter.

In case the string passed as parameter to valueOf() method is not a valid name of one of its constants then a java.lang.IllegalArgumentException is thrown.

Example showing enum's valueOf() method usage
public class EnumTest {
  public static void main(String args[]) {
     Department enumVar = Department.valueOf("HR");
     System.out.println("enumVar == Department.HR? "+(enumVar == Department.HR));
     System.out.println("enumVar equals Department.HR? "+(enumVar.equals(Department.HR)));
  }
}
 OUTPUT of the above code
enumVar == Department.HR?  true
enumVar equals Department.HR?  true
Explanation of the code

  • Example uses the enum Department which we defined in a file of its own.
  • enumVar is a variable of type Department which is assigned the object returned by invoking valueOf() method on Department with "HR" as value for name parameter.
  • On equating enumVar with Department.HR, using both == and Object.equals() method, the enum constants are found be equal.
Determining equality of 2 enum variables Determining equality of 2 enum variables
2 enum variables can be compared with either the ‘==’ or the ‘equals()’ method, without the need to override Object.equals() method in the enum definition.

Benefits of using enums
Enums restrict the values to the defined constants and this is a huge benefit from a system designer’s point of view. A system designed for 4 departments will only allow these 4 values to be assigned to any variable of type Department used anywhere in the whole system. This prevents a lot of potential defects and improves code maintainability.

Moving beyond the basic enum to enhanced enums
Having seen how to define a basic enum and how to use it in code, it is now time to explore the full potential of an enum as a ‘type’. As we understood above, enums are nothing but classes albeit that of a ‘special’ type. So, by virtue of being a class, an enum type can also have methods, variables and constructors defined in it. One can also selectively override method definitions for specific enum constants. Let us look at these advanced features of enums now.

Lets say we need to define a ‘Department Code’ for evey Department enum constant. This code will be alphanumeric and so we will store it as a String. Just like in a class definition, we can create a private instance variable for department code in Department enum, along with a getter method for fetching this value. In addition, we will also define a constructor for passing the department code at the time of defining the enum itself.

The enhanced enum with a new private instance variable deptCode holding the department code, a getter method for deptCode named getDeptCode(), and a constructor which accepts the department code at the time of enum creation would look like this.

Example showing an enum with an instance method, variable, constructor
public enum Department {
  HR("DEPT-01"), OPERATIONS("DEPT-02"), LEGAL("DEPT-03"), MARKETING("DEPT-04");//semi-colon is no longer optional here

  Department(String deptCode){
    this.deptCode=deptCode;
  }

  private String deptCode;

  public String getDeptCode(){
    return deptCode;
  }
}

An important point to note about enum constructors: All enum constructors, including of course the Department enum constructor defined above, are implicitly private. So, even in case there is no access modifier defined for an enum constructor (as is the case in example shown above), the compiler implicitly assumes it to be private. Also, note that defining an enum constructor with public or protected access would result in a compiler error.

To check whether the newly added method, variable and constructor are working fine let us iterate through the Department enum constants using the static values() method we saw earlier and print the department constants along with code.

Example iterates through constants of enum with constructor
public class EnumTest {
  public static void main(String args[]) {

    for(Department dept:Department.values()){
      System.out.println("Department name: "+dept+" Department Code: "+dept.getDeptCode());
    }

  }
}
 OUTPUT of the above code
Department name: HR Department Code: DEPT-01
Department name: OPERATIONS Department Code: DEPT-02
Department name: LEGAL Department Code: DEPT-03
Department name: MARKETING Department Code: DEPT-04
As we can see above, department codes were passed via the constructor and assigned to individual enum constant’s deptCode instance variable, which was then printed correctly when we iterated over Department enum using static values() method.

Enum with selective instance method overrides
To understand this feature of enums, let us now extend the department use case a little. The HR department on seeing the above output where all department codes are accessible publicly has raised an exception to its code being visible to all. It has asked that only its department code should be shielded from any public access attempts such as using the values() method call, and instead of actual deptCode value the string "NOT ACCESSIBLE" be returned.

This requirement now requires us to change the behavior of getDeptCode() method for only the enum constant HR. Fortunately, enum does provide selective override of methods for specific constants. Lets see how it works.

Lets now change our Department enum definition and write a constant specific class body for HR enum constant for overriding the getDeptCode() method. We will then iterate again through the enum constants using values() method, and see if department code for HR is shielded as per requirement or not.

Example showing constant specific class body implementation
//Department.java
public enum Department {
  @Override
  HR("DEPT-01"){
    public String getDeptCode(){
      return "NOT ACCESSIBLE";
    }
  }, OPERATIONS("DEPT-02"), LEGAL("DEPT-03"), MARKETING("DEPT-04");//semi-colon is no longer optional here

  Department(String deptCode){
    this.deptCode=deptCode;
  }

  private String deptCode;

  public String getDeptCode(){
    return deptCode;
  }
}
//EnumTest.java
public class EnumTest {
  public static void main(String args[]) {
   for(Department dept:Department.values()){
     System.out.println("Department name: "+dept+" Department Code: "+dept.getDeptCode());
   }
  }
}
 OUTPUT of the above code
Department name: HR Department Code: NOT ACCESSIBLE
Department name: OPERATIONS Department Code: DEPT-02
Department name: LEGAL Department Code: DEPT-03
Department name: MARKETING Department Code: DEPT-04
As we can see above, the overridden logic for getDeptCode() we specifically added to the enum constant HR in curly braces, did indeed override the default getDeptCode() implementation for only HR enum constant. The code for HR Department was printed in output as "NOT ACCESSIBLE" just as we wanted.

Design Note – In case you want every enum constant to override some method and do it in a mandatory manner, then you can make that method in enum definition as abstract. This will force all enum constants to mandatorily override this method with their own custom logic.

Enums and switch-case
One of the commonly used applications of enums is when deciding between multiple execution paths using switch-case statements. When the decision on which execution path to take can be reduced to a single enum constant value, then using that enum type in switch statement and specifying logic to execute for each of the enum constants of that type using a corresponding case is an efficient option to implement.

The code snippet shown next has a method which prints different outputs for each of the four department types based on which Department enum constant is passed to the switch statement as input. EnumTest class iterates through the Department enum constants using the values() method, so that each of the enum constants is encountered exactly once.

Example showing use of enum in switch-case
public class EnumTest {
  public static void main(String args[]) {
    for (Department dept : Department.values()) {
      switch (dept) {
        case HR:
          System.out.println("Case - HR");
          break;
        case OPERATIONS:
          System.out.println("Case - OPERATIONS");
          break;
        case MARKETING:
          System.out.println("Case - MARKETING");
          break;
        case LEGAL:
          System.out.println("Case - LEGAL");
          break;
      }
    }
  }
}
 OUTPUT of the above code
Case – HR
Case – OPERATIONS
Case – LEGAL
Case – MARKETING

Summary
In the above tutorial we understood enums in their entirety. Starting from the basics we looked at what are enums, how to define an enum, enum constant naming convention, where to define enums, using the static values() and valueOf() method of enums, enum equality and ordinal values. We then looked at enhanced enums containing variables, methods, constructors and constant specific class body. Lastly, we saw how enums can be used to write conditional logic using switch-case statements.

 

Digiprove sealCopyright © 2014-2017 JavaBrahman.com, all rights reserved.