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.
Join the DZone community and get the full member experience.
Join For FreeJava 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
Opinions expressed by DZone contributors are their own.
Comments