Tuesday, April 18, 2023

Switch case vs if-else-if vs Polymorphism in Java - Example Tutorial

Hello guys, conditionals like if-else and switch are very important for programming. After all, programming is for decision making and that's where these conditional programming elements help, but you may have heard that excessive use of if-else and switch is bad and is often taught as code smell. So does that mean, should you never use a switch case in Java? In this article, I will share my thoughts about using switch case vs if-else and then whether we can use Polymorphism to replace if-else in Java and Programming, but before that let's see what is a switch constructor in  Java. A switch construct allows you to choose between multiple options depending upon input,

Benefits of using Switch statement in Java

A switch statement is generally easier to read than repeated else if statements, plus it's less work for you. Of course this only pertains to certain arguments, so you don't end up using it that often.

1. Readability
A switch statement is generally easier to read than repeated else if statement. But, as with many things, it's highly subjective and a matter of both context and preference. You can write really clear if-else trees and really convoluted switch statements, and vice versa. I heard they're good for when if/else statements get bigger than around 4 or 5, plus they seem easier to read.

Switch case vs if-else-if vs Polymorphism in Java



2. Risk
with if-else-if there is good chance that you will forget to use braces and one of the statement will be missed out or always execute. With switch statement, many programmer forget to put break statement, creating subtle fall through bug, which compiler will not able to catch for your.

3. Performance
Correct me if I'm wrong, but they are also translated better into assembly. If I recall correctly, with an if else chain, you have a complexity of O(n) to find the correct predicate, while with a switch statement, the assembly translates into a sort of Binary search to find it, which has a complexity of O(log n).

This is a big advantage, especially when you have large switch statements. Of course, in many cases where people use large switch statements, there are better solutions.

Another advantage is to get rid of the delay a processor gets during pipelining when it fails to predict the outcome of an if/else statement. The processor usually takes a jab at whether it will follow the 'if' path or the 'else' path, and if it guesses incorrectly, there's a lot of cleaning up to do, meaning that a switch would also be a better choice here.

Switching can sometimes be optimized into a Jump Table which is a whole lot faster than a binary search.

if else optimized into a Jump Table



An else-if chain are a more general construct than a switch statement (because the switch does not allow side effects when finding the correct value), but a compiler will recognize an else-if chain that could be a switch statement, and translate both into a branch table if possible. 

The only reason to use a switch statement is if it makes the code more clear to read - this is in fact the reason to use any construct, except for hot-code in performance sensitive applications

Any switch or complex if/else can be replaced with polymorphism... that is the main reason they are considered bad.

It isn't that there's anything wrong with them programmatically, but they are difficult to read (especially when complex or nested) and you can achieve the same end, with a more extensible and human-readable design, by using polymorphism instead.




Example of switch vs if-else vs Polymorphism in Java

Here is an example of using switch and if-else statements with a large number of options. Probably this is not the best example because number of months are fixed and enum is the right data type to represent such values, but I used them to show how clumsy if-else-if code becomes when number of decision point increases.


public class Test {
    public static final int JANUARY = 1;
    public static final int FEBRAUARY = 2;
    public static final int MARCH = 3;
    public static final int APRIL = 4;
    public static final int MAY = 5;
    public static final int JUNE = 6;
    public static final int JULY = 7;
    public static final int AUGUST = 8;
    public static final int SEPTEMBER = 9;
    public static final int OCTOBER = 10;
    public static final int NOVEMBER = 11;
    public static final int DECEMBER = 12;

    public static void main(String... args) {

    }

    public int getNumberOfDays(int month) {
        int days = 30;
        if(month == JANUARY){
            days =  31;
        }else if(month == FEBRAUARY){
            days = 28;
        }else if(month == MARCH){
            days = 31;
        }else if(month == APRIL){
            days = 30;
        }else if(month == MAY){
            days = 31;
        }else if(month == JUNE){
            days = 30;
        }else if(month == JULY){
            days = 31;
        }else if(month == AUGUST){
            days = 31;
        }else if(month == SEPTEMBER){
            days = 30;
        }else if(month == OCTOBER){
            days = 31;
        }else if(month == NOVEMBER){
            days = 30;
        }else if(month == DECEMBER){
            days = 31;
        }
        return days;
    }
   
    public int getNumOfDays(int month){
        int days = 30;
        switch(month){
        case JANUARY:
            days = 31;
            break;
        case FEBRAUARY:
            days = 28;
            break;
        case MARCH:
            days = 31;
            break;
        case APRIL:
            days = 30;
            break;
        case MAY:
            days = 31;
            break;
        case JUNE:
            days = 30;
            break;
        case JULY:
            days = 31;
            break;
        case AUGUST:
            days = 31;
            break;
        case SEPTEMBER:
            days = 30;
            break;
        case OCTOBER:
            days = 31;
            break;
        case NOVEMBER:
            days = 30;
            break;
        case DECEMBER:
            days = 30;
            break;          
         
        }
        return days;
    }
   
    public int getDays(Month month){
        return month.getDays();
    }
   
    public interface Month{
        public int getDays();
    }
   
    public class January implements Month{      
        @Override
        public int getDays() {
            return 30;
        }      
    }
}


but a big switch statement is not good from flexibility and stability point of view. switch statement violets open closed design principle because in order to add new feature you often need to add a new case statement, which means modifying an already tested class. Polymorphism is much better if flexibility is concern. 

By building core logic around interface, you are free to introduce a new implementation anytime without modifying your core logic. Polymorphism allows you to override a method in Java, which means by using same code an appropriate method is called dynamically by JVM

That's all about switch case vs if-else vs Polymorphism in Java. My general rule for switch statements is that they can be tolerated if they appear only once, are used to create polymorphic objects, and are hidden behind an inheritance relationship so that the rest of the system can’t see them. Of course every circumstance is unique, and there are times when I violate one or more parts of that rule

Other Object-Oriented Programming Tutorials from Javarevisited
  • 18 OOP Design Pattern Interview Questions for experienced Programmers (list)
  • How to design a Portfolio Manager for Trade System (Solution)
  • How to design Vending Machine in Java part 2 (tutorial)
  • What is SRP or Single Responsibility Principle? (SRP)
  • How to prepare for System Design Interview (system design prep guide)
  • 7 Best Java Design Pattern courses for Beginners (courses)
  • When to use Decorator design pattern in Java? (Decorator patter)
  • 20 Software design Questions from Programming Interviews (list)
  • How to implement the Builder design pattern in Java? (tutorial)
  • Top 5 Places to learn System Design (system design websites)
  • How to implement a Decorator design pattern in Java? (tutorial)
  • Top 5 System Design Interview Courses for Beginners and Experienced (Courses)
  • Top 5 object-oriented Pattern courses (design pattern courses)
  • How to use the Factory method design pattern in Java? (tutorial)
  • What is the difference between Factory pattern and Dependency Injection in Java? (answer)
  • 5 Books to learn Object-Oriented Design Patterns in Java? (books)
  • 10 System Design Courses for Programmers (system design courses)
Thanks for reading this tutorial; please share it with your friends and colleagues if you like this Object oriented programming tutorial. If you have any feedback or suggestion, then please drop a comment. I would be happy to offer any advise. 

P. S. - If you are new to programming and want to learn Object-oriented programming then you can also check out this list of free OOP courses for beginners. This contains free OOP courses from Udemy, Coursera, and other online portals for beginners. 

1 comment:

  1. You din't mention the new Enhanced Switch statement or the Switch expression. Your days example is so much cleaner a a Switch expression:

    public int getNumOfDays(int month) {
    return switch(month) {
    case SEPTEMBER, APRIL, JUNE, NOVEMBER -> 30;
    case FEBRUARY -> 28;
    default -> 31;
    };
    }
    }

    ReplyDelete