複数の例外型のキャッチと型チェックが改善された例外再スロー

このページでは、次のトピックについて説明します。

複数の例外型の処理

Java SE 7以降では、単一のcatchブロックで複数の例外型を処理できます。この機能により、コードの重複を減らし、広すぎる例外をキャッチしようという試みを減らすことができます。

次の例では、各catchブロックに重複したコードが含まれています。

catch (IOException ex) {
     logger.log(ex);
     throw ex;
} catch (SQLException ex) {
     logger.log(ex);
     throw ex;
}

変数exの型が異なっているため、Java SE 7より前のリリースでは、共通のメソッドを作成して重複したコードをなくすことは困難です。

Java SE 7以降で有効な次の例では、重複したコードをなくすことができます。

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

catch節では、このブロックで処理できる例外の型を、それぞれ縦棒(|)で区切って指定しています。

: catchブロックで複数の例外型を処理する場合、catchパラメータは暗黙的にfinalになります。この例で、catchパラメータexfinalなので、これにcatchブロック内で値を割り当てることはできません。

複数の例外型を処理する1つのcatchブロックをコンパイルしたバイト・コードは、それぞれ1つの例外型のみを処理するcatchブロックを多数コンパイルしたものより小さくなります(したがって、より優れています)。複数の例外型を処理するcatchブロックの場合、コンパイラで生成されるバイト・コードに重複は発生しません。つまり、バイト・コード内に例外ハンドラの繰返しはありません。

型チェックがより包含的になった例外再スロー

Java SE 7のコンパイラでは、再スローされる例外について以前のリリースのJava SEよりも正確な分析が実行されます。これにより、メソッド宣言のthrows節に、より具体的な例外型を指定できます。

次に例を示します。

  static class FirstException extends Exception { }
  static class SecondException extends Exception { }

  public void rethrowException(String exceptionName) throws Exception {
    try {
      if (exceptionName.equals("First")) {
        throw new FirstException();
      } else {
        throw new SecondException();
      }
    } catch (Exception e) {
      throw e;
    }
  }

この例のtryブロックは、FirstExceptionまたはSecondExceptionをスローする可能性があります。rethrowExceptionメソッドの宣言のthrows節でこれらの例外型を指定したい場合について考えます。Java SE 7より前のリリースでは、これは不可能です。catch節の例外パラメータeの型はExceptionであり、catchブロックは例外パラメータeを再スローするため、rethrowExceptionメソッドの宣言のthrows節で指定できるのは例外型Exceptionだけです。

ただし、Java SE 7では、rethrowExceptionメソッドの宣言のthrows節で例外型FirstExceptionおよびSecondExceptionを指定できます。Java SE 7のコンパイラは、文throw eからスローされる例外はtryブロックからのものであること、また、tryブロックからスローされる例外はFirstExceptionおよびSecondExceptionだけであることを判断できます。catch節の例外パラメータeの型がExceptionであっても、コンパイラはこれがFirstExceptionまたはSecondExceptionのインスタンスであることを判断できます。

  public void rethrowException(String exceptionName)
  throws FirstException, SecondException {
    try {
      // ...
    }
    catch (Exception e) {
      throw e;
    }
  }

catchブロック内でcatchパラメータに別の値が割り当てられると、この分析は無効にされます。ただし、catchパラメータに別の値が割り当てられる場合は、メソッドの宣言のthrows節で例外型Exceptionを指定する必要があります。

詳しく説明すると、Java SE 7以降では、catch節で1つ以上の例外型を宣言し、このcatchブロックによって処理される例外を再スローする場合は、再スローされる例外の型が次の条件を満たしているかどうかがコンパイラで確認されます。

Java SE 7のコンパイラを使用する場合は、throwsで宣言されているいずれかの型のスーパー型である例外を再スローできるため、rethrowExceptionメソッドの宣言のthrows節で例外型FirstExceptionおよびSecondExceptionを指定できます。

Java SE 7より前のリリースでは、catch節のいずれかの例外パラメータのスーパー型である例外をスローすることはできません。Java SE 7より前のリリースのコンパイラでは、文throw eで「unreported exception Exception; must be caught or declared to be thrown」というエラーが生成されます。コンパイラは、スローされる例外の型が、rethrowExceptionメソッドの宣言のthrows節で宣言されているいずれかの型に割当て可能かどうかを確認します。しかし、catchパラメータeの型はExceptionであり、これはFirstExceptionおよびSecondExceptionのサブ型ではなくスーパー型です。


Copyright © 1993, 2019, Oracle and/or its affiliates. All rights reserved.