
Exceptions should be used only to denote exceptional conditions; they should not be used for ordinary control flow purposes. Catching an exception is likely to catch unexpected errors; see ERR08-J. Do not catch NullPointerException or any of its ancestors for examples. When a program catches a specific type of exception, it does not know exactly where that exception was thrown. Using a catch
clause to handle an exception that occurs in a known location is a poor solution; it is preferable to handle the error as soon as it occurs—or to prevent it if possible. The nonlocality of throw
statements and corresponding catch
statements can also impede optimizers from improving code that relies on exception handling. Catching exceptions also complicates debugging because exceptions indicate a jump in control flow from the throw
statement to the catch
clause. Finally, exceptions need not be implemented to perform optimally, as it is assumed they are thrown only upon exceptional circumstances. Throwing and catching an exception often yields slower code than does handling the error with some other mechanism.
Noncompliant Code Example
This noncompliant code example attempts to concatenate the processed elements of the strings
array:
public String processString(String string) { // ... return string; } public String processStrings(String[] strings) { String result = ""; int i = 0; try { while (true) { result = result.concat( processString( strings[i])); i++; } } catch (ArrayIndexOutOfBoundsException e) { // Ignore, we're done } return result; }
It uses an ArrayIndexOutOfBoundsException
to detect the end of the array. Unfortunately, since ArrayIndexOutOfBoundsException
is a RuntimeException
, it could be thrown by processString()
without being declared in a throws
clause. So it is possible for processStrings()
to terminate before all of the strings are processed.
Compliant Solution
This compliant solution uses a standard for
loop to concatenate the strings. In this case, the ArrayIndexOutOfBoundsException
can occur only under some exceptional circumstances and can be handled outside of normal processing.
public String processStrings(String[] strings) { String result = ""; try { for (int i = 0; i < strings.length; i++) { result = result.concat( processString( strings[i])); } } catch (ArrayIndexOutOfBoundsException e) { // Handle error } return result; }
Technically this code need not catch ArrayIndexOutOfBoundsException
because it is a runtime exception. In fact, this code should not catch ArrayIndexOutOfBoundsException
unless the method has a particular way of handling it (that differs from handling any other exception class). Otherwise, this code should just let the exception propagate up the call stack.
Applicability
Use of exceptions for any purpose other than detecting and handling exceptional conditions complicates program analysis and debugging, degrades performance, and can increase maintenance costs.
Bibliography
[Bloch 2001] | Item 39, "Use Exceptions Only for Exceptional Conditions" |
[JLS 2011] | Chapter 11, "Exceptions" |