catch语句块处理一种或多种类型的异常,并以改进的异常类型检查方式来重新抛出异常。

我们先来看一段代码:


1. catch (IOException ex) {
2.      logger.log(ex);
3.      throw ex;
4. catch (SQLException ex) {
5.      logger.log(ex);
6.      throw ex;
7. }


ex存在不同的类型,因此想要创建一个公共方法来清除重复的代码是非常困难的。不过从Java SE 7版本开始,你可以编写如下代码来去除重复的代码:

1. //多个异常类型之间用"|"隔开
2. catch (IOException|SQLException ex) {
3.     logger.log(ex);
4.     throw ex;
5. }


注意:如果一个catch语句块处理的异常类型超过1个,那就隐式地表示被catch的参数变量(例如上面的ex)是一个final的变量,你不能在catch语句块内对其重新赋值。catch语句块处理多种异常类型比使用多个catch语句块,每个语句块只处理一种类型的异常所编译生成的字节码更小,因此也更好。一个处理多个异常类型的catch语句块在被Java编译器编译时并不会生成重复的字节码,字节码中也没有重复的异常处理程序。编译器能够对再次抛出的异常(rethrown exception)做出更精确的分析。这使得你可以在一个方法声明throws从句中指定更具体的异常类型。我们先来看下面的一个例子:


    1. static class FirstException extends Exception { }
    2. static class SecondException extends Exception { }
    3. 
    4. public void rethrowException(String exceptionName) throws Exception {
    5.     try {
    6.         if (exceptionName.equals("First")) {
    7.             throw new FirstException();
    8.         } else {
    9.             throw new SecondException();
    10.         }
    11.     } catch (Exception e) {
    12.         throw e;
    13.     }
    14. }


    try语句块可能会抛出FirstException或者SecondException类型的异常。设想一下,你想在rethrowException方法声明的throws从句中指定这些异常类型。在Java SE 7之前的版本,你无法做到。因为在catch子句中的异常参数e是java.lang.Exception类型的,catch子句对外抛出异常参数e,你只能在rethrowException方法声明的throws从句中指定抛出的异常类型为java.lang.Exception (或其父类java.lang.Throwable)。rethrowException方法声明的throws从句中指定抛出的异常类型为FirstException和SecondException。Java SE 7的编译器能够判定这个被throw语句抛出的异常参数e肯定是来自于try子句,而try子句只会抛出FirstException或SecondException类型的异常。尽管catch子句的异常参数e是java.lang.Exception类型,但是编译器可以判断出它是FirstException或SecondException类型的一个实例:

    1. public void rethrowException(String exceptionName) throws FirstException, SecondException {
    2.     try {
    3.         // ...
    4.     }
    5.     catch (Exception e) {
    6.         throw e;
    7.     }
    8. }

    catch捕获的异常变量在catch子句中被重新赋值,那么异常类型检查的分析将不会启用,因此在这种情况下,你不得不在方法声明的throws从句中指定异常类型为java.lang.Exception。catch子句中声明一种或多种类型的异常,并且重新抛出这些被捕获的异常时,需符合下列条件,编译器才会对再次抛出的异常进行类型验证:try

    • 子句会抛出该异常。

    catch

    • 子句捕获该异常。

    catch

    • 子句捕获的多个异常中的一个异常类型的父类或子类。