Tuesday, 9 December 2014

Enum Data Types in Java

Background

Sometime we need to program to restrict use inputs. Lets take a scenario - you are opening a pet store. As a starter you decide only to provide  - Dogs, Cats and Parrots. Next you have to design a Java program to provide the pet to customers. One way would be as follows - 

class PetStore {
    
    public static final String CATEGORY_DOGS = "Dogs";
    public static final String CATEGORY_CATS = "Cats";
    public static final String CATEGORY_PARROTS = "Parrots";
    
    public void getPet(String petType) {
        switch(petType){
        case CATEGORY_DOGS : System.out.println("You are opting for a pet Dog");
                            break;
        case CATEGORY_CATS : System.out.println("You are opting for a pet Cat");
                            break;
        case CATEGORY_PARROTS : System.out.println("You are opting for a pet Parrot");
                            break;
        default : System.out.println("We do not provide other pet animals");
        }
    }
}


It serves the purpose. But it does not stop user from entering Lion, Tiger does it ? Program would fall back to default saying we do not provide other pet Animals. But Lion, Tiger are not pet in the first place. One way to restrict user input is declaring an Enum. Lets come to that.



Using Enums

enum PetTypes {
    DOGS,CATS,PARROTS
}

class PetStore {
    
    public void getPet(PetTypes petType) {
        switch(petType){
        case DOGS : System.out.println("You are opting for a pet Dog");
                            break;
        case CATS : System.out.println("You are opting for a pet Cat");
                            break;
        case PARROTS : System.out.println("You are opting for a pet Parrot");
                            break;
        }
    }
}

Now you have successfully restricted user from entering one of the three allowed values. That is not it Enums has other advantages too.Lets come to those. Lets say you also need to store the number of available pet of each category. You can store that in enum too. Each enum value can have multiple attributes.


enum PetTypes {
    DOGS(10),CATS(7),PARROTS(9);
    
    int availableUnits;
    
    //enum constructors are implicitly private
    PetTypes(int availableUnits) {
        this.availableUnits = availableUnits;
    }

    public int getAvailableUnits() {
        return availableUnits;
    }
    
}

class PetStore {
    
    public void getPet(PetTypes petType) {
        switch(petType){
        case DOGS : System.out.println("You are opting for a pet Dog.");
                            break;
        case CATS : System.out.println("You are opting for a pet Cat");
                            break;
        case PARROTS : System.out.println("You are opting for a pet Parrot");
                            break;
        }
        System.out.println("Available units are : " + petType.getAvailableUnits());
    }
}


You can test it by

    public static void main(String args[])
    {
        new PetStore().getPet(PetTypes.CATS);
    }


You will get :

You are opting for a pet Cat
Available units are : 7

Note : When you say DOGS(10), corresponding constructor is called i.e PetTypes(10).

Enums are better than a bunch of constants because it provides type‐safe
checking.

Important Points

  • Enums are implicitly private, static and final. 
  • Each declared enum implicitly inherits java.lang.Enum.
  • You can use valueOf() and name() methods on enums.
  • You can compare enums with == operator.
  • You cannot use new operator on enums. Not even inside enum definition. Outside you cannot because constructor is implicitly private. 
  • Enums cannot be local meaning you cannot declare them inside a method. They should be declared and defines inside of a top level class or an interface.

Question : 

 1. What happens when you compile the following code - 

enum PetTypes {
    int availableUnits;             //  #1
    DOGS(10),CATS(7),PARROTS(9);    //  #2
    
    //enum constructors are implicitly private
    PetTypes(int availableUnits) {
        this.availableUnits = availableUnits;
    }

    public int getAvailableUnits() {
        return availableUnits;
    }
 }

Above enum definition is incorrect and will not compile. You need to declare enum elements first before any other attributes. In short you need to interchange line #1 and #2 for above code to compile. (JLS reference)
NOTE : You can also create an enum from a String. This is helpful when working with older
code. The String passed in must match exactly, though.

Eg.

PetTypes s1 = PetTypes.valueOf("DOGS"); // DOGS
PetTypes s2 = PetTypes.valueOf("dogs"); // exception



NOTE : The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.

NOTE : Another thing that you can’t do is extend an enum. The values in an enum are all that are allowed. You cannot add more at runtime by extending the enum.

You can also have abstract method in an enum in which case each enum will have to implement the abstract method -

    public enum PetTypes {
        DOGS {
            public void printHours() { System. out .println("9am-3pm"); }
        }, CATS {
            public void printHours() { System. out .println("9am-5pm"); }
        }, PARROTS {
            public void printHours() { System. out .println("9am-7pm"); }
        }, RABBIT {
            public void printHours() { System. out .println("9am-5pm"); }
        };
        public abstract void printHours();
    }


If we don’t want each and every enum value to have a method, we can create a default
implementation and override it only for the special cases:

     public enum PetTypes {
        DOGS {
            public void printHours() { System. out .println("9am-3pm"); }
        }, CATS {
            public void printHours() { System. out .println("9am-5pm"); }
        }, PARROTS , RABBIT ;
        public void printHours() { System. out .println("9am-9pm"); };
    } 
  
NOTE : If in your enum class all you have are types of that enums you can skip the semicolon. So you can do something like -

    enum Flavors {
        VANILLA, CHOCOLATE, STRAWBERRY
    }


But you cannot do something like -

    enum Flavors {
        VANILLA, CHOCOLATE, STRAWBERRY //not allowed, need semicoln here
       
        Flavors(){}
    }


This will give compilation error. If you have anything more than enum declarations you need to add a semicolon. Also as stated earlier enums should be the 1st thing in the enum structure.

NOTE : The ordinal() method of an enum returns its corresponding int value. Like arrays,
enums are zero based. Remember that the index of an enum may change when you recompile
the code and should not be used for comparison.

Related Links
t> UA-39527780-1 back to top