Java Language Exceptions and exception handling Catching an exception with try-catch

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Extensions
> Step 2: And Like the video. BONUS: You can also share it!

Example

An exception can be caught and handled using the try...catch statement. (In fact try statements take other forms, as described in other examples about try...catch...finally and try-with-resources.)

Try-catch with one catch block

The most simple form looks like this:

try {
    doSomething();
} catch (SomeException e) {
    handle(e);
}
// next statement

The behavior of a simple try...catch is as follows:

  • The statements in the try block are executed.
  • If no exception is thrown by the statements in the try block, then control passes to the next statement after the try...catch.
  • If an exception is thrown within the try block.
    • The exception object is tested to see if it is an instance of SomeException or a subtype.
    • If it is, then the catch block will catch the exception:
      • The variable e is bound to the exception object.
      • The code within the catch block is executed.
      • If that code throws an exception, then the newly thrown exception is propagated in place of the original one.
      • Otherwise, control passes to the next statement after the try...catch.
    • If it is not, the original exception continues to propagate.

Try-catch with multiple catches

A try...catch can also have multiple catch blocks. For example:

try {
    doSomething();
} catch (SomeException e) {
    handleOneWay(e)
} catch (SomeOtherException e) {
    handleAnotherWay(e);
}
// next statement

If there are multiple catch blocks, they are tried one at a time starting with the first one, until a match is found for the exception. The corresponding handler is executed (as above), and then control is passed to the next statement after the try...catch statement. The catch blocks after the one that matches are always skipped, even if the handler code throws an exception.

The "top down" matching strategy has consequences for cases where the exceptions in the catch blocks are not disjoint. For example:

try {
    throw new RuntimeException("test");
} catch (Exception e) {
    System.out.println("Exception");
} catch (RuntimeException e) {
    System.out.println("RuntimeException");
}

This code snippet will output "Exception" rather than "RuntimeException". Since RuntimeException is a subtype of Exception, the first (more general) catch will be matched. The second (more specific) catch will never be executed.

The lesson to learn from this is that the most specific catch blocks (in terms of the exception types) should appear first, and the most general ones should be last. (Some Java compilers will warn you if a catch can never be executed, but this is not a compilation error.)

Multi-exception catch blocks

Java SE 7

Starting with Java SE 7, a single catch block can handle a list of unrelated exceptions. The exception type are listed, separated with a vertical bar (|) symbol. For example:

try {
    doSomething();
} catch (SomeException | SomeOtherException e) {
    handleSomeException(e);
} 

The behavior of a multi-exception catch is a simple extension for the single-exception case. The catch matches if the thrown exception matches (at least) one of the listed exceptions.

There is some additional subtlety in the specification. The type of e is a synthetic union of the exception types in the list. When the value of e is used, its static type is the least common supertype of the type union. However, if e is rethrown within the catch block, the exception types that are thrown are the types in the union. For example:

public void method() throws IOException, SQLException
    try {
        doSomething();
    } catch (IOException | SQLException e) {
        report(e);
        throw e;
    }

In the above, IOException and SQLException are checked exceptions whose least common supertype is Exception. This means that the report method must match report(Exception). However, the compiler knows that the throw can throw only an IOException or an SQLException. Thus, method can be declared as throws IOException, SQLException rather than throws Exception. (Which is a good thing: see Pitfall - Throwing Throwable, Exception, Error or RuntimeException.)



Got any Java Language Question?