java.svg

【Java】例外処理

Java

例外とは

例外とは、コンパイルではエラーにならないが、実行した際に発生するエラーのことです。 例えば、ファイルの読み込み処理でファイルが読み込めない、参照した値が存在しないなどさまざまな例外が考えられます。

後述しますが、プログラム上ではthrowという単語で例外が発生したことを表します。 そのため例外が発生することは、「例外が投げられる」や「例外がスローされる」と表現されます。

例外処理は、例外がスローされた場合にどのような処理を行うかを定義します。

検査例外と非検査例外

例外には、検査例外と非検査例外の 2 種類があります。

検査例外は、例外が発生した場合の処理、いわゆる例外処理を必ず定義しなければいけません。 言い方を変えると、例外処理を強制させる例外になります。

一方非検査例外は、例外処理を定義してもしなくてもよいという例外になります。 一般的には非検査例外が使用されることが多いです。

例外クラス

Java では、例外クラスというものがあり、クラスによってどのような例外が発生したかを表します。 すべての例外クラスは、Throwableクラスをスーパークラスとしており、大きく以下の 3 つの例外に分けられます。

Error

Errorクラスは、Throwableのサブクラスで、アプリケーション内で処理するべきでない重大な例外を表します。 そのためErrorクラスは、非検査例外に該当します。

通常のアプリケーション開発では、あまり使用しない例外だと思います。

Exception

Exceptionクラスは、Throwableのサブクラスで、すべての検査例外のサブクラスになります。 Exceptionのサブクラスには、以下のようなものがあります。

例外クラス説明
IOExceptionなんらかの入出力に関する例外
SQLExceptionデーベースへのアクセスや操作に関する例外
ClassNotFoundException指定したクラス名のクラスがなかった場合の例外
NoSuchFieldException指定したフィールド名がクラスになかった場合の例外
NoSuchMethodException指定したメソッド名がクラスになかった場合の例外

RuntimeException

RuntimeExceptionクラスは、Exceptionのサブクラスで、Error以外のすべての非検査例外のサブクラスになります。 RuntimeExceptionのサブクラスには、以下のようなものがあります。

例外クラス説明
IndexOutOfBoundsException配列などでインデックスが範囲を超えた場合の例外
NullPointerExceptionnullのオブジェクトに対して処理を実行しようとした場合などの例外
IlligalArgumentException不正な引数を渡した場合の例外
ArrayStoreException配列に不正なオブジェクトを追加しようとした場合の例外
ClassCastExceptionクラスがキャストできない場合の例外

例外処理の定義

try-catch

例外処理は、以下のようにtrycatchを使用して定義します。

try {
  // 例外が発生する可能性のある処理
} catch (Exception e) {
  // 例外時の処理
}

catchには、実際に発生した例外クラスを指定します。 スーパークラスを指定することもできますが、一般的には発生した例外そのものを指定します。

検査例外がスローされる処理は、必ずcatchで例外処理を定義する必要があります。

非検査例外がスローされる処理は、catchするかは任意となります。 catchしなかった場合は、呼び出し元の処理へと例外が伝搬されます。

複数例外

例外が複数スローされる場合は、以下のように複数catchを指定するか、|で繋げます。

try {
  // ...
} catch (IOException | SQLException e) {
  // 例外時の処理
} catch (NullPointerException e) {
  // 例外時の処理
}

finally

finallyは、例外が発生してもしなくても必ず最後に行う処理を定義します。 ファイルのクローズ処理などで使用されます。

try {
  // ...
} catch (Exception e) {
  // 例外時の処理
} finally {
  // 最後に実行する処理
}

例外のスロー

throws

メソッドの定義で、どのような例外がスローされるかをthrowsを使って定義します。

public void doProcess() throws IOException, SQLException, NullPointerException {
  //例外が発生する処理
}
try {
  doProcess();
} catch (IOException | SQLException e) {
  // 例外時の処理
} catch (NullPointerException e) {
  // 例外時の処理
}

throw

throwは、意図的に例外をスローする場合に使用します。

public void doProcess() throws IOException, SQLException, NullPointerException {
  if (!condition) {
    throw new NullPointerException();
  }
}

独自例外

例外は、継承することで独自の例外を作成することができます。 基本的に、検査例外とする場合はExceptionを、非検査例外とする場合はRuntimeExceptionを継承します。 意味や用途の近い例外がある場合は、それを継承します。

コンストラクターは、必要なものだけ定義します。 以下はExceptionのコンストラクターを基に作成しています。

public class MyException extends RuntimeException {
  private static final long serialVersionUID = 1L;

  public MyException() {
    super();
  }

  public MyException(String message) {
    super(message);
  }

  public MyException(String message, Throwable cause) {
    super(message, cause);
  }

  public MyException(Throwable cause) {
    super(cause);
  }

  protected MyException(String message, Throwable cause,
                              boolean enableSuppression,
                              boolean writableStackTrace) {
      super(message, cause, enableSuppression, writableStackTrace);
  }
}
public void doProcess() throws MyException {
  if (!condition) {
    throw new MyException();
  }
}
try {
  doProcess():
} catch (MyException e) {
  // 例外処理
}