Java SE 7 (released on July 2011) introduces a couple of enhancement/change for exception handling method. The first one allows catching multiple exception types in a single catch clause, and the second one allows re-throwing subtypes of the exception declared in the throws clause. Let’s see these changes in details.
Consider the following Java code snippet:
try { doSomeRiskyThings(); } catch (IOException ex) { LOGGER.log(ex); } catch (SQLException ex) { LOGGER.log(ex); } catch (CustomException ex) { LOGGER.log(ex); }
The method doSomeRiskyThings() may throws the three exception types: FileNotFoundException, IOException, and SQLException which are caught by the three separate catch blocks, but each block does the same thing (e.g. logging the exceptions and/or re-throwing them). This looks cluttered and duplicated and redundant. So in Java 7, we can catch all these three exception types in a single catch block like this:
try { doSomeRiskyThings(); } catch (IOException | SQLException | CustomException ex) { LOGGER.log(ex); }
This improvement is called multi-catch statement, in which each exception is separated by the vertical bar symbol (|). Of course we can combine both regular catch and multi-catch like this:
try { doSomeRiskyThings(); } catch (IOException | SQLException ex) { LOGGER.log(ex); } catch (CustomException ex) { // do another stuff with this custom exception }
There are two noteworthy rules regarding the multi-catch statement:
} catch (IOException | SQLException ex) { ex = new SQLException(); }
The compiler will throw this error: multi-catch parameter ex may not be assigned
} catch (FileNotFoundException | IOException ex) { LOGGER.log(ex); }
The compiler will throw this error (no matter the order is): Alternatives in a multi-catch statement cannot be related by subclassing
The Exception class is the supertype of all exceptions, thus we also cannot write:
} catch (IOException | Exception ex) { LOGGER.log(ex); }
Before Java SE 7, it is illegal to write the following code:
// this is illegal before Java SE 7 void doSomeRiskyThings() throws CustomException1, CustomException2 { try { if (errorNumber == 1) { throw new CustomException1(); } else { throw new CustomException2(); } } catch (Exception ex) { throw ex; } }
Because the catch block re-throws the exception of type Exception, so the throws clause must declare to throw the Exception type, like this:
// this is legal before Java SE 7 void doSomeRiskyThings() throws CustomException1, CustomException2, Exception { try { if (errorNumber == 1) { throw new CustomException1(); } else { throw new CustomException2(); } } catch (Exception ex) { throw ex; } }
Or this:
// this is legal before Java SE 7 void doSomeRiskyThings() throws Exception { try { if (errorNumber == 1) { throw new CustomException1(); } else { throw new CustomException2(); } } catch (Exception ex) { throw ex; } }
However, since Java SE 7, we can declare to throw subtypes of the exceptions (in the throws clause) that are re-thrown in the catch blocks, like this:
// this is legal since Java SE 7 void doSomeRiskyThings() throws CustomException1, CustomException2 { try { if (errorNumber == 1) { throw new CustomException1(); } else { throw new CustomException2(); } } catch (Exception ex) { throw ex; } }
In other words, we can re-throw an exception which is a supertype of the exception types declared in the throwsclause.