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
.)
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:
try
block are executed.try
block, then control passes to the next statement after the try...catch
.try
block.
SomeException
or a subtype.catch
block will catch the exception:
e
is bound to the exception object.catch
block is executed.try...catch
.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.)
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.)