Friday, August 17, 2012

JAVA enum tutorial

Java language has supported enum type for several releases. Yet, many programmers do not use it or do not fully understand all features of enum.

We still see a lot of code like this:

public static final int LIGHT = 1 ;
public static final int MEDIUM = 2 ;
public static final int HEAVY = 3 ;
public static final int SUPERHEAVY = 4 ;

int weight_range  = getRange():
if (weight_range == LIGHT  ) {

} else if (weight_range == MEDIUM) {

} else if (weight_range == HEAVY) {

}

Such code is error prone. It lacks type safety. If the weight_range is serialized/deserialized somewhere you are going to have to remember what 1,2,3 represent.

Java enum is a cleaner type safe way of working with constants. It is a type that has a fixed set of constant fields that are instances of the type.

1. Defining enum

Defining enum is like defining a class.

public enum WeightRange {
 LIGHT, MEDIUM, HEAVY,SUPERHEAVY 
} ;

defines a WeightRange enum type with 4 constant fields.

2. Creating a variable of type enum

WeightRange wclass = WeightRange.Medium ;

is like declaring any other type.

3. Using the enum

WeightRange boxer_class  = getWtRangeFromSomeWhere();

if (boxer_class == WeightRange.LIGHT) {

} else if (boxer_class == WeightRange.HEAVY) {

}

is more type safe than the code without enums.

4. Enum is a class.

As mentioned above, enum is a class. Every enum type extends java.lang.Enum.  All enum types thus can have additional fields and constructors.

The above WeightRange enum can be enhanced to add fields for low and high range. The values are provided in the constructor.

public enum WeightRange {
   
    LIGHT(0,70) ,
    MEDIUM(71,150),
    HEAVY(151,225),
    SUPERHEAVY(226,350) ;
   
    private final int low ;
    private final int high ;   
   
    WeightRange(int low, int high) {       
        this.low = low ;
        this.high = high ; 
    }
}

5. Enum can also have methods.

In the above enum we can add a method to check if a given weight is within a weight range.

public boolean isInRange(int wt) {       
        if (wt >= low && wt <= high)
            return true ;
        else
            return false ;
}

5. It can have static factory method that takes a weight as parameter and returns the correct enum.

public static WeightRange getWeightRange(int weight) {
       
        if (weight <= 70)
            return LIGHT ;
        else if (weight <= 150)
            return MEDIUM ;
        else if (weight <= 225)
            return HEAVY ;
        else
            return SUPERHEAVY ;        
}

6.  Calling toString on an enum value returns the name used to define the constant field.

System.out.println(WeightRange.LIGHT) ; 
prints LIGHT

7. In converse, enum can be constructed using a String using the valueOf method.

WeightRange w3 = WeightRange.valueOf("MEDIUM") ;
System.out.println(w3) ;
will print MEDIUM

8. You can iterate over the constants defined in the enum.

for (WeightRange r : WeightRange.values()) {
            System.out.println(r) ;
}

9. enum constants are final.

WeightRange.LIGHT = WeighRange.Heavy ; // compilation error

10. The only instances of an enum that can be created are the constants defined in the enum defintion.

WeightRange r = new WeightRange(12,100) ; // compilation error

Next time you need a fixed set of constants, consider using enum. It is type safe, leads to better code and your constants are within a namespace.