Exceptions should be used only to denote exceptional conditions; they should not be used for ordinary control flow purposes. Catching a generic object such as Throwable 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 always know from where that exception was thrown. Using a catch clause to handle an exception that occurs in a distant 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. Relying on catching exceptions for control flow also complicates debugging because exceptions indicate a jump in control flow from the throw statement to the catch clause. Finally, exceptions need not be highly optimized, as it is assumed that they are thrown only in exceptional circumstances. Throwing and catching an exception frequently has worse performance than handling the error with some other mechanism.
Noncompliant Code Example
This noncompliant code example attempts to concatenate the processed elements of the strings array:
| Wiki Markup |
|---|
{{exception}} is used to improve program readability and reliability by detecting exceptional situation and possibly recover from it. However, it should not be used abusively to act as part of routine functionality. Irregular usage of exception will interrupt normal execution flow and degrade system performance\[[Effective Jave, item 39|http://books.google.com/books?id=ZZOiqZQIbRMC&pg=PA169&lpg=PA169&dq=item+39+use+exceptions&source=bl&ots=UZP26ufK15&sig=E60s65pIGPpYY7O79U96dx_oAqg&hl=en&ei=QLHzSsPFMMOZlAe3ioSiAw&sa=X&oi=book_result&ct=result&resnum=1&ved=0CAgQ6AEwAA#v=onepage&q=item%2039%20use%20exceptions&f=false]\]. |
Noncompliant Code Example
In the following example, the program tries to use ArrayIndexOutOfBoundsException to detect the end of array and then proceed with its ongoing logic.
| Code Block | ||
|---|---|---|
| ||
trypublic { String processSingleString(String int i = 0;string) { while(true)// ... a[i++].next()return string; } public catchString processStrings(ArrayIndexOutOfBoundsExceptionString[] estrings) { String result // end of array, ongoing routine } |
| Wiki Markup |
|---|
This is not recommended because it didn't comply with the main purpose of using exception, which is to detect and recover \[[EXC03-J. Try to gracefully recover from system errors|EXC03-J. Try to gracefully recover from system errors]\]. The normal logical flow of reaching the end of array is treated as an exception here, which has an inverse effect on readability and comprehension. Besides, exception-based idiom is far slower than standard code block in Java VM. It will prevents certain optimizations that JVM would otherwise perform. |
Compliant Solution
A standard way of using for idiom can solve the problem.
| Code Block | ||
|---|---|---|
| ||
for (int i=0; i<a.length; i++) {
a[i].f();
}
|
Noncompliant Code Example
In another sense, an exposed API should not force its clients to use exceptions for ordinary control flow. A class that has state-dependent method should also have a state-testing method to accompany it, so as to decide whether the first method should be called. In the following example, because iterator class didn't has a hasNext() method, the caller is forced to use exception to detect the end of iterator.
| Code Block | ||
|---|---|---|
| ||
try {
Iterator i = collection.iterator();
while(true) {
Foo foo = (foo) i.next();
}
} catch (NoSuchElementException e) {
// ongoing routine
}
|
Compliant Solution
A simple fix will be to implement a hasNext() method in the iterator class.
= "";
int i = 0;
try {
while (true) {
result = result.concat(processSingleString(strings[i]));
i++;
}
} catch (ArrayIndexOutOfBoundsException e) {
// Ignore, we're done
}
return result;
} |
This code uses an ArrayIndexOutOfBoundsException to detect the end of the array. Unfortunately, since ArrayIndexOutOfBoundsException is a RuntimeException, it could be thrown by processSingleString() without being declared in a throws clause. So it is possible for processStrings() to terminate prematurely before processing all of the strings.
Compliant Solution
This compliant solution uses a standard for loop to concatenate the strings.
| Code Block | ||
|---|---|---|
| ||
public String processStrings(String[] strings) {
String result = "";
for (int i = 0; i < strings.length; i++ | ||
| Code Block | ||
| ||
for (Iterator i = collection.iterator(); i.hasNext();) { Fooresult foo = (Foo) i.next(= result.concat( processSingleString( strings[i])); } return ...result; } |
Risk Assessment
The abusive usage of exception can result in performance degrade and poor logical flow design.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
EXC10- J | low | unlikely | medium | P3 | L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
| Wiki Markup |
|---|
\[[Effective Jave, item 39|http://books.google.com/books?id=ZZOiqZQIbRMC&pg=PA169&lpg=PA169&dq=item+39+use+exceptions&source=bl&ots=UZP26ufK15&sig=E60s65pIGPpYY7O79U96dx_oAqg&hl=en&ei=QLHzSsPFMMOZlAe3ioSiAw&sa=X&oi=book_result&ct=result&resnum=1&ved=0CAgQ6AEwAA#v=onepage&q=item%2039%20use%20exceptions&f=false]\]
\[[Java Reference 05|AA. Java References#JLS 05]\] |
This code need not catch ArrayIndexOutOfBoundsException because it is a runtime exception, and such exceptions indicate programmer errors, which are best resolved by fixing the defect.
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 2013] | Chapter 11, "Exceptions" |
...
CON02-J. Facilitate thread reuse by using Thread Pools 11. Concurrency (CON) CON04-J. Do not call overridable methods from synchronized regions