{{announcement.body}}
{{announcement.title}}

Why You Should Avoid Using Exceptions as the Control Flow in Java

DZone 's Guide to

Why You Should Avoid Using Exceptions as the Control Flow in Java

Ever used exceptions as the control flow in Java? Well, you probably shouldn't. Here's why.

· Java Zone ·
Free Resource

Exceptions as control flow

Learn more about using exceptions as control flow in Java.

Java is a general-purpose programming language with many alternatives to solving a certain problem. However, there are best practices that need to be followed, and there are some bad practices out there as well that are still commonly used.

One of these common bad practices is using exceptions as the control flow. This should be avoided for two reasons: It reduces the performance of your code as a response per unit time, and it makes your code less readable.

You may also like: Exceptions in Java: You're (Probably) Doing It Wrong

Let's start by looking at how one can use an exception as the control flow by viewing the following example code. The business case for the code is:

    public static int findAge(String name) {
        try {
            String ageAsString = findUser(name);
            return ageAsString.length();
        } catch (NameNotFoundException e) {
            return 0;
        }
    }

    private static String findUser(String name) {
        if(name==null) {
            throw new NameNotFoundException();
        }
        return name;
    }


If the client provides a non-null name to the findAge method, it returns the length of the name, but if the user name is null, then the findUser method will throw a NameNotFoundException, and in that case, the findAge method  will return 0.

How can one refactor this code without an exception? Frankly, there multiple ways to do so, but only one of them is provided here.

    public static int findAgeNoEx(String name) {
        String ageAsString = findUserNoEx(name);
        return ageAsString.length();
    }

    private static String findUserNoEx(String name) {
        if(name==null) {
            return "";
        }
        return name;
    }


To find out the performance impact of exception, I prepared the following code which calls 10M times both implementation and it is seen that the exception costs thousands of milliseconds on my Intel Core i7-3630QM CPU.

public class ControlFlowWithExceptionOrNot {
    public static class NameNotFoundException extends RuntimeException {
        private static final long serialVersionUID = 3L;
    }

    private static final int TRIAL = 10000000;

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        for (int i = 0; i < TRIAL; i++) {
            findAgeNoEx(null);
        }
        System.out.println("Duration :" + (System.currentTimeMillis() - start));

        long start2 = System.currentTimeMillis();
        for (int i = 0; i < TRIAL; i++) {
            findAge(null);
        }
        System.out.println("Duration :" + (System.currentTimeMillis() - start2));
    };

    public static int findAge(String name) {
        try {
            String ageAsString = findUser(name);
            return ageAsString.length();
        } catch (NameNotFoundException e) {
            return 0;
        }
    }

    private static String findUser(String name) {
        if (name == null) {
            throw new NameNotFoundException();
        }
        return name;
    }

    public static int findAgeNoEx(String name) {
        String ageAsString = findUserNoEx(name);
        return ageAsString.length();
    }

    private static String findUserNoEx(String name) {
        if (name == null) {
            return "";
        }
        return name;
    }

}


Output:

Duration :16
Duration :6212


If we compare the two findAge methods in terms of readability, the one without exception is crystal clear, whatever the findUser method returns, take its length, and we are sure that the  findUser method will return a string. However, the one with the exception is a bit confusing: The return of the findUser method is not clear. It may return a string, or it may throw an exception, and from the method's signature, it is not visible. For this reason, the functional programming paradigm does not welcome exceptions. 

Finally, it would be better if you use an exception when there is a real exceptional case. If you use exceptions for the control flow, it may cause performance issues and your code may be less readable. 

Hope this helps! Please share your thoughts in the comments section.

Further Reading

Nine Best Practices to Handle Exceptions in Java

Exceptions in Java: You're (Probably) Doing It Wrong

Making an Exception-Handling Mechanism

Topics:
java ,exception ,control flow ,handling ,java exceptions

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}