Because an exception is caught by its type, it is better to define exceptions for specific purposes than to use the general exception types for multiple purposes. Throwing general exception types makes code hard to understand and maintain and defeats much of the advantage of the Java exception-handling mechanism.

Noncompliant Code Example

This noncompliant code example attempts to distinguish between different exceptional behaviors by looking at the exception's message:

try {
    doSomething();
} catch (Throwable e) {
  String msg = e.getMessage();
  switch (msg) {
    case "file not found":
      // Handle error
      break;
    case "connection timeout":
      // Handle error
      break;
    case "security violation":
      // Handle error
      break;
    default: throw e;
  }
}

If doSomething() throws an exception or error whose type is a subclass of Throwable, the switch statement allows selection of a specific case to execute. For example, if the exception message is "file not found," the appropriate action is taken in the exception-handling code.

However, any change to the exception message literals involved will break the code. For example, suppose this code is executed:

throw new Exception("cannot find file");

This exception should be handled by the first case clause, but it will be rethrown because the string does not match any case clause.

Furthermore, exceptions may be thrown without a message.

This noncompliant code example falls under ERR08-J-EX0 of ERR08-J. Do not catch NullPointerException or any of its ancestors because it catches general exceptions but rethrows them.

Compliant Solution

This compliant solution uses specific exception types and defines new special-purpose exception types where required.

public class TimeoutException extends Exception {
  TimeoutException () {
    super();
  }
  TimeoutException (String msg) {
    super(msg);
  }
}

// ...

try {
    doSomething();
} catch (FileNotFoundException e) {
  // Handle error
} catch (TimeoutException te) {
  // Handle error
} catch (SecurityException se) {
  // Handle error
}

Applicability

Exceptions are used to handle exceptional conditions. If an exception is not caught, the thread will be terminated, which may cause the program to exit. An exception that is incorrectly caught or is caught at the wrong level of recovery will often cause incorrect behavior.

Automated Detection

ToolVersionCheckerDescription
Parasoft Jtest
2023.1
CERT.ERR51.NCEDo not catch exception types which are too general or are unchecked exceptions
SonarQube
9.9
S1193


Bibliography



5 Comments

  1. I am unable to understand the following:

    For example, if a maintainer were to edit the throw expression to read throw new Exception("file not found");, the exception would be rethrown by the code of the noncompliant code example rather than handled.

    First it seems like a dumb thing for the maintainer to do this especially in the default case. Second, so what? I might want upper layers to handle this exception.

    Am not marking this as reviewed until this is resolved.

    1. I adjusted that text because the throw clause was supposed to throw something besides "file not found". I won't argue about if this is a dumb thing to do, I'll simply argue that people have tried it, so its OK for us to use a NCCE that tries to match exceptions based on their message text, and why this is a Bad Thing.

      1. After fixing the string it makes sense (that was the reason it looked like a dumb odd mistake to make). Thanks.

  2. The statement

    If an exception is not caught, the program will be terminated.

    is only true for single threaded programs. In general, only the current thread is terminated. See also JLS §11.3:

    If no catch clause that can handle an exception can be found, then the current thread (the thread that encountered the exception) is terminated.

     

    1. Good catch, I've modified the text.