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

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

複数の例外型の処理

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, 2013, Oracle and/or its affiliates. All rights reserved.