Thursday, February 9, 2017

Switch statement implementation for class type using enum


Switch statement in most languages including Java, C++, C# etc. is a kind of jump table. It is considered when you have a long if-else ladder. It is considered faster than if-else ladder because conditions can be looked up directly. Whereas in if-else ladder each condition will be evaluated until a true condition is met.

JVM loads the cases (condition values) and compares with the input value and allows to jump to the case without evaluating each case (condition). That's the reason it is faster than if-else ladder.
Each case (condition) has a "break" statement which allows the execution to exit once condition is fulfilled.

It is recommended to use switch statement if the "if-else" ladder is long (has more than 3 conditions).

As per Oracle documentation:

"Unlike if-then and if-then-else statements, the switch statement can have a number of possible execution paths. A switch works with the byteshortchar, and int primitive data types. It also works with enumerated types (discussed in Enum Types), the String class, and a few special classes that wrap certain primitive types: CharacterByteShort, and Integer (discussed in Numbers and Strings)."

Java doesn't support switch statement for Classes other than mentioned above. But there may be cases when you want to use switch statement. We will see the usage here by taking a problem statement.

Let's say i have a Shape interface and there are multiple implementations of the Shape. And i have a requirement to call a method from one of the implementation class which matches the given instance using "instanceof" operator.

e.g.

 
if(shape instanceof Square) {

    shape.printShape();

} else if (shape instanceof Rectangle) {

    shape.printShape();

} else if (shape instanceof Triangle) {

    shape.printShape();

} else if (shape instanceof Circle) {

    shape.printShape();

} else if (shape instanceof Cube) {

    shape.printShape();

} .....
...... and so on.



Now if i want to use switch statement here then it's not supported directly. But there some design patterns which can be followed to achieve the goal. Here we will use java enum type to solve our problem.

Let's take same example as given above and try to solve the problem using enum.
We will do following steps:

1- We will create an enum type where we will declare enum constants as class types.
2- We will declare a map which will be populated with class names of above declared enums.
3- We will declare a method which will return the class type constant based on given name (string)


//ShapesEnum.java
package com.switchtest;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public enum ShapesEnum {

       SQUARE(Square.class), RECTANGLE(Rectangle.class), CIRCLE(Circle.class);

       private final String className;

       ShapesEnum(final Class<?> cls) {
             this.className = cls.getName();
       }

       //Initialize a map which will store the class names of all shape types
       private static final Map<String, ShapesEnum> SHAPES =
                             new ConcurrentHashMap<String, ShapesEnum>();

       //Populate the map with values
       static {
             for (final ShapesEnum shape : values()) {
                    SHAPES.put(shape.className, shape);
             }
       }

       public static ShapesEnum getShape(final String className) {
             return SHAPES.get(className);
       }
}



//Shape.java
package com.switchtest;

public interface Shape {
       void displayName();
}




//Square.java
package com.switchtest;


public class Square implements Shape {
      
       @Override
       public void displayName() {
             System.out.println("I am Square..");
       }

}

  
//Rectangle.java
package com.switchtest;


public class Rectangle implements Shape {
      
       @Override
       public void displayName() {
             System.out.println("I am Rectangle..");
       }

}

//Circle.java
package com.switchtest;

public class Circle implements Shape{

       @Override
       public void displayName() {
             System.out.println("I am Circle..");          
       }
}


//SwitchTest.java
package com.switchtest;

public class SwitchTest {
       public static void main(String[] argv) throws Exception {
             final Shape square = new Square();
             printShape(square);
            
             final Shape rectangle = new Rectangle();
             printShape(rectangle);
            
             final Shape circle = new Circle();
             printShape(circle);
       }

       private static void printShape(final Shape shape) {
             switch (ShapesEnum.getShape(shape.getClass().getName())) {
             case SQUARE:
                    shape.displayName();
                    break;
             case RECTANGLE:
                    shape.displayName();
                    break;
             case CIRCLE:
                    shape.displayName();
                    break;
             default:
                    System.out.println("No shape selected.");
                    break;
             }
       }
}



Output:

I am Square..
I am Rectangle..
I am Circle..