Saturday, March 31, 2012

Enums demystified

Why enums came into picture?

Before enums came into picture we all were using constants for different values.
There would be a constant file in which we define values like this

public static final int LOW=1;
public static final int MEDIUM=2;
public static final int HIGH=3;

Above approach works,but there are following issues.These are:-
i)Programmer is not bounded to use the constants.Programmer can put any int value and code will work fine.
ii)LOW/MEDIUM/HIGH are just variable names. So when we print LOW/MEDIUM/HIGH it prints 1/2/3 which does not convey any meaning.

So java introduced enums.Enum is like a class or interface which is used to define a set of constants.Enum constants can't be changed once created and we are free to add behavior to it by adding abstract methods and interfaces.It provides type safety and can be used inside a switch statement.Moreover they are initialized when enum class is loaded.



Plain enums

Plain enum are constants without any parametrized value.In the current example-GenderEnum we are having two constants M,F for male and female gender respectively.

package com.kunaal.enumDetails;

/**
 * @author KunaalATrehan
 *
 */
public enum GenderEnum {
 M,F;
}


Parametrized enums



Plain enum do provide type safety.However to provide more meaningful implementation we have to use overloaded constructor of the enum.

Lets take the example of Income group enum.Here by using parametrized enum we are able to convey the meaning of enum constant more effectively.

package com.kunaal.enumDetails;

/**
 * @author KunaalATrehan
 *
 */
public enum IncomeGroupEnum {
 BPL("Below Poverty Line"),
 LIG("Lower Income Group"),
 MIG("Middle Income Group"),
 HIG("High Income Group");
 
 //Variable for data val
 private String dataVal;

 /**
  * @return the dataVal
  */
 public String getDataVal() {
  return dataVal;
 }

 /**
  * Parameterized constructor
  * @param dataVal
  */
 private IncomeGroupEnum(String dataVal) {
  this.dataVal = dataVal;
 }

}








Are enums similar to normal java classes?

Enums are exactly like java classes.Enums can implement an interface and can have abstract methods.In order to understand it better,lets take an example.

Here we are creating an enum for educational qualifications.This enum has an abstract method called print(). This abstract print() method is overridden by each enum value.

package com.kunaal.enumDetails;

/**
 * @author KunaalATrehan
 *
 */
public enum EducationDtlEnum {
  PG("Post Graduate") {
   @Override
   public void print() {
    System.out.println("Person may have done MBA,MCA,MS or similar things");
   }
  },
  UG("Under Graduate") {
   @Override
   public void print() {
    System.out.println("Person may have done Diploma. ");
   }
  },
  GRAD("Graduate") {
   @Override
   public void print() {
    System.out.println("Person may have done BE,BTech,BSC,BBA or similar things");
   }
  },
  HS("High School") {
   @Override
   public void print() {
    System.out.println("Person has finished the high school");
   }
  },
  PHD("Doctorate") {
   @Override
   public void print() {
    System.out.println("Person may have doen PHD,MD or similar things.");
   }
  };
  
  //Variable for dataval
  private String dataVal;
  
  /**
   * Parameterized constructor
   * @param value
   */
  private EducationDtlEnum(String value){
   this.dataVal=value;
  }

  /**
   * @return the dataVal
   */
  public String getDataVal() {
   return dataVal;
  }
  
  //Abstract print method
  public abstract void print();
}


Enum example using plain,parametrized and enums with abstract method

Person class containing following variables
-String variable for name
-Plain enum 'GenderEnum' for capturing person's gender
-Parametrized enum 'IncomeGroupEnum' for capturing person's income group
-Parametrized enum 'EducationDtlEnum' with abstract method print()

package com.kunaal.enumDetails;

/**
 * @author KunaalATrehan
 *
 */
public class Person {
 
 //Enum for education details
 private EducationDtlEnum educationInfo;
 
 //Enum for income group
 private IncomeGroupEnum incomeGroup;
 
 //Variable for name
 private String name;
 
 //Variable for gender
 private GenderEnum genderEnum;

 /**
  * @return the genderEnum
  */
 public GenderEnum getGenderEnum() {
  return genderEnum;
 }

 /**
  * @param genderEnum the genderEnum to set
  */
 public void setGenderEnum(GenderEnum genderEnum) {
  this.genderEnum = genderEnum;
 }

 /**
  * @return the educationInfo
  */
 public EducationDtlEnum getEducationInfo() {
  return educationInfo;
 }

 /**
  * @param educationInfo the educationInfo to set
  */
 public void setEducationInfo(EducationDtlEnum educationInfo) {
  this.educationInfo = educationInfo;
 }

 /**
  * @return the incomeGroup
  */
 public IncomeGroupEnum getIncomeGroup() {
  return incomeGroup;
 }

 /**
  * @param incomeGroup the incomeGroup to set
  */
 public void setIncomeGroup(IncomeGroupEnum incomeGroup) {
  this.incomeGroup = incomeGroup;
 }

 /**
  * @return the name
  */
 public String getName() {
  return name;
 }

 /**
  * @param name the name to set
  */
 public void setName(String name) {
  this.name = name;
 }
 
 /**
  * Overridden toString() method
  */
 @Override
 public String toString() {
  return "Person [educationInfo=" + educationInfo + ", genderEnum="
    + genderEnum + ", incomeGroup=" + incomeGroup + ", name="
    + name + "]";
 }
}

Enum example making different concrete implementation of Person class.
This example contains different methods to test different functionalities provided by enum.
i.e
-printValues() prints enumeration value.
-refCheck(..) checks for == implementation.
-abstractEnumMthdImpl(...) invokes overridden abstract method in different enums.
-defaultToString(..) invokes toString() method of the enum
-equalityChk(..) checks for equals implementation.

package com.kunaal.enumDetails;

/**
 * @author KunaalATrehan
 *
 */
public class EnumExample {

 /**
  * @param args
  */
 public static void main(String[] args) {
  Person person=new Person();
  person.setName("Mr. A");
  person.setEducationInfo(EducationDtlEnum.PHD);
  person.setIncomeGroup(IncomeGroupEnum.HIG);
  person.setGenderEnum(GenderEnum.M);
  
  Person person2=new Person();
  person2.setName("Mrs. B");
  person2.setEducationInfo(EducationDtlEnum.PHD);
  person2.setIncomeGroup(IncomeGroupEnum.HIG);
  person2.setGenderEnum(GenderEnum.F);
  
  Person person3=new Person();
  person3.setName("Mr. C");
  person3.setEducationInfo(EducationDtlEnum.PG);
  person3.setIncomeGroup(IncomeGroupEnum.MIG);
  person3.setGenderEnum(GenderEnum.M);
  
  //print enum data 
  printValues();
  
  //chk for references
  refCheck(person, person2, person3);
  
  //testing interface mthd  implementation
  abstractEnumMthdImpl(person, person2, person3);
  
  //testing default toString method
  defaultToString(person,person2,person3);
  
  //testing equals method
  equalityChk(person,person2,person3);
  
  //invoke toString() on person objects
  System.out.println(person);
  System.out.println(person2);
  System.out.println(person3);
 }
 
 /**
  * This method print values of the enumeration 
  */
 private static void printValues(){
  System.out.println("----Enumeration values-------");
  
  for(EducationDtlEnum data:EducationDtlEnum.values()){
   System.out.println(data);
  }
  System.out.println("---------------------------------------");
 }
 
 /**
  * This method checks whether enum objects are created once 
  * or created for every reference.
  * 
  * @param person
  * @param person2
  * @param person3
  */
 private static void refCheck(Person person,Person person2,Person person3){
  System.out.println("Checking for reference ==");
  System.out.println("---------------------------------------");
  System.out.println(person.getEducationInfo()==(person2.getEducationInfo()));
  System.out.println(person.getEducationInfo()==(person3.getEducationInfo()));
  System.out.println("---------------------------------------");  
 }
 
 /**
  * Here our custom enum has an abstract method print whose implementations are provided
  * by all the enums.We are invoking that method.
  * 
  * @param person
  * @param person2
  * @param person3
  */
 private static void abstractEnumMthdImpl(Person person,Person person2,Person person3){
  System.out.println("Get print implementations");
  System.out.println("------------------------------------");
  person.getEducationInfo().print();
  person2.getEducationInfo().print();
  person3.getEducationInfo().print();
  System.out.println("------------------------------------");  
 }
 
 /**
  * This method invokes the default toString() method of enum
  * 
  * @param person
  * @param person2
  * @param person3
  */
 private static void defaultToString(Person person,Person person2,Person person3){
  System.out.println("Get toString() implementations");
  System.out.println("---------------------------------------");
  System.out.println(person.getEducationInfo().toString());
  System.out.println(person2.getEducationInfo().toString());
  System.out.println(person3.getEducationInfo().toString());
  System.out.println("---------------------------------------");
  
 }
 
 /**
  * This method invokes the default equals method of enum
  * 
  * @param person
  * @param person2
  * @param person3
  */
 private static void equalityChk(Person person,Person person2,Person person3){
  System.out.println("Equality check");
  System.out.println("---------------------------------------");
  System.out.println(person.getEducationInfo().equals(person2.getEducationInfo()));
  System.out.println(person.getEducationInfo().equals(person3.getEducationInfo()));
  System.out.println("---------------------------------------");
  
  
 }

}

Output of the above code

----Enumeration values-------
PG
UG
GRAD
HS
PHD
---------------------------------------
Checking for reference ==
---------------------------------------
true
false
---------------------------------------
Get print implementations
------------------------------------
Person may have doen PHD,MD or similar things.
Person may have doen PHD,MD or similar things.
Person may have done MBA,MCA,MS or similar things
------------------------------------
Get toString() implementations
---------------------------------------
PHD
PHD
PG
---------------------------------------
Equality check
---------------------------------------
true
false
---------------------------------------
Person [educationInfo=PHD, genderEnum=M, incomeGroup=HIG, name=Mr. A]
Person [educationInfo=PHD, genderEnum=F, incomeGroup=HIG, name=Mrs. B]
Person [educationInfo=PG, genderEnum=M, incomeGroup=MIG, name=Mr. C]