Everything about enum data type in Java

hamidur01

Hamidur Rahman

Posted on April 13, 2020

Everything about enum data type in Java

The goal of this article is to expose one to the enum data type in Java. I hope by reading this one would learn something new or brush up their knowledge on Java enum data type. So, let’s dive in.

The reason behind this article?

Well, I have been using enum without knowing essential knowledge about that. Recently, in an interview, I was asked, can an enum have a constructor and instance variables? I could not answer. The actual answer is yes. So, I decided to learn as much as I can on enum and share with others to let fall for the common pitfalls.

What is the enum data type?

As by javadoc -

An enum type is a special data type that enables for a variable to be a set of predefined constants.

In other words, an enum data type is a set of constants and grouped together.

An enum is just class type as we create classes in Java but with a different special keyword enum and essentially do work as a simple Java class. All enum type implicitly extends Enum from java.lang package and can implement an interface(s) as well as an enum can have constructors, instance variables and methods. Every constant you defined in an enum will be public static final by default. Every enum constant has an index number called ordinal number. An ordinal number is just number that defines the position of that specific enum constant. The ordinal number starts with 0 as an array in most languages.

One VERY dangerous miss conception would be - if an enum can have a constructor then I can create an instance of an enum using the new keyword. NO - you CANNOT instantiate an enum type but wait then why would an enum have a constructor? I will answer that later in this article.

Let’s create a very basic enum type. Let’s take the measurement Size as an example of an enum. When a company makes clothes they define there own size of their clothes (yes, there are some standard sizes but let’s not think of that).

public enum Size
{
   SMALL,       // 0
   MEDIUM,      // 1
   LARGE,       // 2

   EXTRA_SMALL,     // 3
   EXTRA_EXTRA_SMALL,   // 4

  EXTRA_LARGE,      // 5
  EXTRA_EXTRA_LARGE // 6

}

All the Sizes defined inside Size are enum constants of type Size.

As we can see that if we have more than one constants then they are separated by commas and the last one does not have any semicolon, although putting one at the end does not affect anything but it's mandatory when we use constructor and instance variables.

So, how do we access them? Since all constants are implicitly public static final, we can use the enum type - Size to access it.

Size small = Size.SMALL;
Size extraSmall = Size.EXTRA_SMALL;
System.out.println(small);
System.out.println(extraSmall);

will output -

SMALL
EXTRA_SMALL

respectively to the console.

Wait! Hold on, Size.EXTRA_SMALL is going to need more space in our clothes, more ink means more cost. So, why not symbolize them to reduce all the overhead. To do that we are slightly going to refactor our enum - Size and that’s when we are going to use a contractor and an instance variable(s).

public enum Size
{
   SMALL("S"),          // 0
   MEDIUM("M"),         // 1
   LARGE("L"),          // 2

   EXTRA_SMALL("XS"),            // 3
   EXTRA_EXTRA_SMALL("XXS"),      // 4

   EXTRA_LARGE("XL"),            // 5
   EXTRA_EXTRA_LARGE("XXL");       // 6

   private final String value;

   Size(String value)
   {
       this.value = value;
   }

   public String getValue()
   {
       return value;
   }
}

Things to notice - a final instance variable ‘value’, an overloaded constructor with implicit private access modifier. Public and protected are NOT allowed as they would allow you to instantiate. And finally, a getter method to get the value of an enum constant.

Now, thanks to the instance variable, constructor, and getter method we can reduce our cost and print something like this -

Size extraSmall = Size.EXTRA_SMALL;
Size extraExtraLarge = Size.EXTRA_EXTRA_LARGE;

System.out.println(extraSmall.getValue());
System.out.println(extraExtraLarge.getValue());

will output -

XS
XXL

respectively to the console.

A value can also be directly accessed/passed to others like

System.out.println(Size.MEDIUM.getValue());  // M

Now, what if your company decides that not only we are going to display the letters/symbol of a Size, for customer convenience we will display the size in inches next to the Size letter/symbol. Well, no worries we won’t have to drastically change or create another enum for size. We can do so like this -

public enum Size
{
   SMALL("S", 6),          // 0
   MEDIUM("M", 8),         // 1
   LARGE("L", 10),          // 2

   EXTRA_SMALL("XS", 4),            // 3
   EXTRA_EXTRA_SMALL("XXS", 2),      // 4

   EXTRA_LARGE("XL", 12),            // 5
   EXTRA_EXTRA_LARGE("XXL", 14);       // 6

   private final String value;
   private final int inches;

   Size(String value, int inches)
   {
       this.value = value;
       this.inches = inches;
   }

   public String getValue()
   {
       return value;
   }

   public int getInches()
   {
       return inches;
   }
}

Now a Size enum instance has 2 attributes called value and inches.

What about Ordinal number and other types of methods?

Let’s start with the ordinal number. As mentioned the ordinal number is nothing but the position of the constants. Let’s organize our Size constants from smallest to largest by inches.

...
EXTRA_EXTRA_SMALL("XXS", 2),      // 0
EXTRA_SMALL("XS", 4),            // 1
SMALL("S", 6),          // 2
MEDIUM("M", 8),         // 3
LARGE("L", 10),          // 4
EXTRA_LARGE("XL", 12),            // 5
EXTRA_EXTRA_LARGE("XXL", 14);       // 6
...

Everything else is the same. To get the ordinal number/index number of an enum constant Size -

System.out.println(Size.MEDIUM.ordinal()); 

Will print 3 to the console as MEDIUM in the 4 positions.
The ordinal() is a method available to Size instance.

There are 2 important methods available to the enum type Size along with others. They are called valueOf(string) and values().

values() return an array of enum type ex. Size and since it returns an array we can index it or iterate it, as by our needs.

System.out.println(Size.values()[0]); // EXTRA_EXTRA_SMALL

System.out.println(Size.values().length); // 7

And Size.valueOf(“string”) will take a string argument and will return an instance of that enum type ex. Size that has the same name as “string”, if not found by the name then IllegalArgumentException will the thrown.

More rarely, an enum type can also have abstract methods.

public enum Size
{
   EXTRA_EXTRA_SMALL("XXS", 2){
       @Override
       public String formatMyWay()
       {
           return EXTRA_EXTRA_SMALL.getValue()+" - " + EXTRA_EXTRA_SMALL.getInches() + "\"";
       }
   };

   public abstract String formatMyWay();

   // everything else is the same as before
}

Well, that’s all about enum from my end. I hope this was helpful and if I missed something please feel free to collaborate. Happy coding!

References:

JavaDoc
Oracle Java Tutorial

💖 💪 🙅 🚩
hamidur01
Hamidur Rahman

Posted on April 13, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related