前回は、try・catchを使って、例外が発生したときに対応する方法を学習しました。
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("計算中に問題が発生しました。");
}
tryで例外が発生する可能性のある処理を囲み、catchで例外に対応します。
今回は、さらに例外処理を理解するために、finallyとthrowsについて学習しましょう。
finallyは、例外が発生したかどうかにかかわらず、通常の制御の流れでtry・catchの処理を抜ける際に実行されるブロックです。
例えば、次のコードを見てみましょう。
public class Main {
public static void main(String[] args) {
try {
System.out.println("処理を開始します。");
} catch (Exception e) {
System.out.println("例外が発生しました。");
} finally {
System.out.println("処理を終了します。");
}
}
}
処理を開始します。
処理を終了します。
例外が発生していませんが、finallyの中の処理も実行されています。
finallyは、例外の有無にかかわらず、後片付けなどの処理を行いたい場合に利用できます。
次は、例外が発生する場合を確認してみましょう。
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("0で割ることはできません。");
} finally {
System.out.println("後片付けを行います。");
}
}
}
0で割ることはできません。
後片付けを行います。
tryの中で例外が発生すると、残りの処理は中断され、対応するcatchが実行されます。
その後、finallyの処理が実行されます。
例外が発生しても、通常はfinallyの処理が実行されることを覚えておきましょう。
ただし、JVMの強制終了など、通常の制御の流れを外れる状況では、finallyが実行されないこともあります。
finallyは、処理の最後に必ず行いたい後片付けなどに利用されます。
ただし、ファイルなどのリソースを扱う場合は、Javaのtry-with-resourcesを利用すると、リソースの解放をより簡潔に記述できます。詳しくはファイル操作の記事でも紹介します。
throwsは、メソッド内で発生する可能性のある例外を、呼び出し元に処理してもらうために宣言する仕組みです。
例えば、ファイル操作などでは、例外が発生する可能性があります。
次のコードでは、throwsを使って例外を呼び出し元へ伝えています。
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
readData();
}
public static void readData() throws IOException {
System.out.println("データを読み込みます。");
}
}
この例では、readData()とmain()にthrows IOExceptionを記述しています。
throwsは、メソッドが指定した例外を呼び出し元へ伝える可能性があることを宣言するものです。
なお、この例のreadData()は実際には例外を発生させません。throwsの書き方を示すための例です。
例外が発生する可能性のある処理に対しては、状況に応じてtry・catchで処理する方法と、throwsで呼び出し元へ伝える方法があります。
try {
// 例外が発生する可能性のある処理
} catch (IOException e) {
System.out.println("入出力で問題が発生しました。");
}
この場合、指定したIOExceptionが発生すると、catchの処理を実行します。
public static void readData() throws IOException {
// 例外が発生する可能性のある処理
}
この場合、メソッド内でIOExceptionを処理せず、呼び出し元に処理を委ねることができます。
呼び出し元でも、try・catchで処理するか、条件に応じてさらにthrowsで伝える必要があります。
throwとthrowsは似ていますが、役割が異なります。
throwは、例外を実際に発生させるために使用します。
throw new IllegalArgumentException("不正な値です。");
このコードでは、IllegalArgumentExceptionを発生させています。
throwsは、メソッドの宣言部分に記述し、例外を呼び出し元へ伝える可能性があることを示します。
public static void checkValue(int value)
throws IOException {
// 処理
}
この例は、IOExceptionを呼び出し元へ伝える可能性があることを宣言しています。
Javaの例外には、大きく分けてチェック例外と非チェック例外があります。
コンパイラによって処理や宣言が求められる例外です。一般的には、IOExceptionなどが該当します。
チェック例外が発生する可能性のある処理では、try・catchで処理するか、throwsで宣言する必要があります。
コンパイラによる捕捉・宣言が必須ではない例外です。RuntimeExceptionとそのサブクラスが該当します。
非チェック例外でも、原因を調べて適切に対応することが大切です。
finallyは後片付けなどの処理を行うための仕組みです。例外そのものを処理するcatchとは役割が異なります。
throwsは例外を解決するものではなく、呼び出し元へ伝えるための宣言です。
throwは例外を発生させるために使い、throwsはメソッドの宣言部分に記述します。
例外処理では、例外をどこで処理するのか、どこまで伝えるのかを考えることが重要です。
次回は、文字列を扱うためのStringクラスについて学習します。