【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 | 配列などでインデックスが範囲を超えた場合の例外 |
NullPointerException | null のオブジェクトに対して処理を実行しようとした場合などの例外 |
IlligalArgumentException | 不正な引数を渡した場合の例外 |
ArrayStoreException | 配列に不正なオブジェクトを追加しようとした場合の例外 |
ClassCastException | クラスがキャストできない場合の例外 |
例外処理の定義
try-catch
例外処理は、以下のようにtry
、catch
を使用して定義します。
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) {
// 例外処理
}