Skip to main content
  1. Articles/

When to Use Enums Instead of If-else or Switch Statements to Make the Code Cleaner?

·3 mins
Mayukh Datta
Technical Java Spring Boot

We usually use if-else or switch statements to write our logical conditions in our code. There is nothing to worry about as long as your list of logical conditions is short. It’s when the list of logical conditions you need to place starts growing, the if-else or switch ladder becomes longer and, it gets messy.

The readability and the maintainability factor of the code get reduced. It’s a difficult job to maintain such a long if-else or switch ladder and it’s prone to logical errors. If we are only comparing String values with if-else or switch statements, then we can make use of enums instead.

Suppose we’ve got a bunch of strings that we pass through our API’s request and based on those strings we call particular methods in our Spring Boot application. We use if-else or switch statements to know which strings are present in the request and then execute the logical blocks inside those statements.

Here is a part of the request body where we are passing an array of strings.

{
    "options": ["TOTAL_ASSIGNED_COUNT", 
                "TOTAL_CUSTOMER_COUNT"]
}

And, here is the if-else construct to read the options array, check the String values and call corresponding methods to get the data and send them in the response.

@Service
public class GetDataService {
    
    public List<Integer> fetchData() {
        String[] options = request.getOptions();
        List<Integer> resultList = new ArrayList<>();

        for(String option : options) {
            if(option.equals("TOTAL_ASSIGNED_COUNT")) {
                resultList.add(getTotalAssignedCount());
            }else if(option.equals("TOTAL_CREATED_COUNT")) {
                resultList.add(getTotalCreatedCount());
            }else if(option.equals("TOTAL_CUSTOMER_COUNT")) {
                resultList.(getTotalCustomerCount());
            }else if(option.equals("TOTAL_ORDER_COUNT")) {
                resultList.add(getTotalOrderCount());
            }else if ...
            and this goes on ....
        }

        return resultList;
    }
}

We can have hundreds of such options in our code and to process them we will need to write a huge if-else ladder. That’s clearly not a clean and efficient code. A single String option value inside the for loop is let to fall through the if-else ladder until any logical condition gets satisfied.

Let’s see how we can make this better by using enums.

public enum OptionsProcessor {
    TOTAL_ASSIGNED_COUNT {
        @Override
        public int getData(SomeDao someDao) {
            return someDao.getTotalAssignedCount();
        }
    },
    TOTAL_CREATED_COUNT {
        @Override
        public int getData(SomeDao someDao) {
            return someDao.getTotalCreatedCount();
        }
    },
    TOTAL_CUSTOMER_COUNT {
        @Override
        public int getData(SomeDao someDao) {
            return someDao.getTotalCustomerCount();
        }
    },
    TOTAL_ORDER_COUNT {
        @Override
        public int getData(SomeDao someDao) {
            return someDao.getTotalOrderCount();
        }
    };

    public abstract int getData(SomeDao someDao);
}

So we have moved the actions/operations in the enum and now we can use the valueOf() method on the enum to get hold of enum constants that matches the String values in our options array and call their getData() method. The lookup using the valueOf() method takes \(O(1)\) time to find the enum constant. It uses enum ordinals which are auto-generated integer sequence numbers that provide random access on an internally generated enum constants array. This is more time-efficient than the if-else alternative. The lookup mechanism scenario would be the same for a switch-case alternative but the solution using enum is better maintainable and readable.

Here is the code where we are hitting the enum constants and their methods:

@Service
class GetDataService {

    @Autowired
    SomeDao someDao;

    public List<Integer> fetchData() {
        String[] options = request.getOptions();
        List<Integer> resultList = new ArrayList<>();

        for(String option : options) {
            resultList.add(OptionsProcessor.valueOf(option).getData(someDao));
        }

        return resultList;
    }
}

We can add more methods to the enum to have more functionalities without breaking any existing code. You will get to discover how much beneficial this technique is, once you start using it. This is quite similar to the strategy design pattern using enums.