例外処理
コンパイルエラー
プログラムコードの中のづつりの間違いや文法の誤りは、コンパイル時に検知され、コンパイルエラーという形で知らされる。
ランタイムエラー
コンパイルは問題なくできたものの、プログラムを実行させたときに発生するエラー
プログラムを実行している途中に発生するこのようなトラブルや、それを表すものをJava 言語では例外(exception) と言う。
例外が起きたことは「例外が発生する」のほか、「例外が投げられる」「例外がスロー(throw) される」 などと表現される。
例外が投げられる原因はさまざまだが基本的には、「想定外のことが起きて、そのまま処理を継続できない」という状況が発生したときに例外が投げられる。
public class ExcepentionExample{
public static void main(String[]args){
int a =4;
int b =0;
int c = a /b;
System.out.println("cの値は" + c);
System.out.println("処理を正常に終了します");
}
}
上の例文では文法に間違いのでないのでコンパイルエラーは発生しないが4➗0という計算できない値になっているので例外が投げられて処理が中断し以下のようなエラー分が出る
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExcepentionExample.main(ExcepentionExample.java:5)
このような単純なプログラムであれば、エラーによってプログラムが中断しても大した問題はないが重要な処理を行うプログラムの場合、問題が発生したからといって、プログラムが止まってしまっては困ることがある。
そのため、Javaプログラムには例外が投げられたときにキャッチして処理を続けることができる仕組みがある
Javaの持つ例外処理メカニズムでは,処理の実行中にエラーが発生した場合にエラーの内容を表す例外オブジェクトと呼ばれるオブジェクトをエラー通知に使う。
このときの処理を例外処理といい、例外をキャッチするには、次のようなtry 〜 catch 文を使う。
// tryブロック
try{
例外が投げられる可能性があるが本来実行したい処理
}
// catchブロック
catch(例外オブジェクトの型 引数){
例外が投げられた時の処理(例外が発生しなければ行われない処理)
}
// finallyブロック
finally{
例外の有無に関わらず、最後に必ず実行される処理
}
tryブロックの中に例外が発生する可能性のある処理を記述し、catchブロックの中に例外が発生した後の処理を記述し、例外が投げられた場合、それ以降の処理をスキップしてcatch ブロックの中に処理が移る。
catch ブロックの引数には、投げられた例外の種類を表*例外オブジェクトが渡されるため、catchブロックの引数には、変数の宣言と同じように型と変数名を指定する。
例外が投げられても投げられなくても、finallyブロックに記述した処理は、try-catch 文の最後に必ず実行される。(finallyブロックは必要がなければ省略することができる。)
public class ExceptionExample3{
public static void main(String[]args){
int a =4;
int b =0;
try{
int c = a /b;
System.out.println("cの値は" + c);
}
catch(ArithmeticException e){
System.out.println("例外をキャッチします");
System.out.println(e);
return;
}
finally{
System.out.println("finallyブロックの処理です");
}
System.out.println("プログラムを終了します");
}
}
例外をキャッチします
java.lang.ArithmeticException: / by zero
finallyブロックの処理です
tryブロック内で計算が合わない式があるのでcatchブロック内の処理が実行される。
catchブロックの例外オブジェクトの型に指定している「ArithmeticException」は数値の計算において、不正な算術処理(例えば数学的にあり得ない「ゼロ除算(10÷0 など)」)が行われた場合にエラー通知をする例外オブジェクト。引数eにはエラー内容の文が代入されるるのでcatchブロック内のSystem.out.println(e)メソッドで「java.lang.ArithmeticException: / by zero」が出力される。
catchブロック内の最後でreturn;としているので通常であればmainメソッドは終了されるがfinallyブロック内の処理は最後に必ず実行されるので「finallyブロックの処理です」が出力される
複数の例外オブジェクト
例外オブジェクトを使ってエラーの通知をすることを、例外を投げる(スロー,throw) と言う。
Java 言語のプログラムの中で実際に投げられるものは例外オブジェクトで、 例外オブジェクトの実体は、java.lang パッケージに含まれるExceptionクラスのサブクラスのインスタンスになる。
Exceptionクラス自体は、Throwableクラスのサブクラス(Throwable は英語で「投げることができる」という意味。Throwableクラスはjava.lang パックージに含まれている)。
このようなExceptionクラスを中心とした継承関係は、次の図のような階層になっている。
発生した原因に応じて、投げられる例外オブジェクトの種類は異なるがtry - catch 文では、引数の異なるcatch ブロックを並べることで、発生した例外の種類に応じた例外処理ができるようになる。
try{
例外が投げられる可能性があるが本来実行したい処理
}
catch(例外オブジェクトの型1 引数1){
例外が投げられた時の処理1
}
catch(例外オブジェクトの型2 引数2){
例外が投げられた時の処理2
}
:
:
finally{
例外の有無に関わらず、最後に必ず実行される処理
}
上から順番に見ていって、最初に例外の型が一致したcatchブロックが実行される。
tryブロックの中で投げられた例外オブジェクトのクラスが「例外の型1」に該当する場合には、「例外が投げられたときの処理1」が実行されます。「例外の型1」ではなく「例外の型2」に該当する場合には、「例外が投げられたときの処理2」が実行される。(catchブロックはいくつでも並べることができる。)
例外オブジェクトを自作する
例外オブジェクトは自分で作成して投げる(throwする)ことができ、作成した例外オブジェクトを、メソッドの外へ投げることも出来る。
独自の例外クラスを作成する場合、既存の例外クラスを継承する必要があり、一般的には例外を表すExceptionクラスを継承する。
Exceptionクラスには引数には例外の内容を表すメッセージ(文字列)を指定できるコンストラクタがある。
通常のオブジェクトと同様にコンストラクタを呼び出し文字列を渡せる。
生成した例外オブジェクトは、throwキーワードを使って投げることが出来る。
// コンストラクタ
Exception(String message)
// 新しい例外オブジェクトeを生成し文字列を渡す
Exception e = new Exception("◯◯という例外が発生しました");
// 例外の内容を表すメッセージ(文字列)が入った例外オブジェクトeをthrow文を使って投げる
throw e;
次のように記述するとオブジェクト生成の記述を省略して変数を使わずに直接投げることが出来る。
throw new Exception("◯◯という例外が発生しました");
例文
class InvalidAgeException extends Exception{
InvalidAgeException(String message){
super(message);
}
}
public class MyExceptionExample{
public static void main(String[]args){
int age = -10;
try{
if (age < 0) {
throw new InvalidAgeException("年齢にマイナスの値が指定されました");
}
System.out.println("年齢は" + age + "歳です");
}
catch(InvalidAgeException e){
System.out.println("例外をキャッチします");
System.out.println(e);
}
}
}
例外をキャッチします
InvalidAgeException: 年齢にマイナスの値が指定されました
InvalidAgeExceptionクラス
InvalidAgeExceptionクラスは既存の例外オブジェクトであるExceptionクラスを継承した独自の例外オブジェクトでExceptionクラスの処理を使える事が出来る。
2行目でコンストラクタを宣言し、superキーワードを使ってスーパークラスであるExceptionクラスのコンストラクタを呼び出している。
MyExceptionExampleクラス
mainメソッド内の変数ageに-10の値を入れたのでtry文の中で例外が発生して「throw new InvalidAgeException」の記述で例外オブジェクトが生成され直接、例外の内容を表すメッセージが投げられcatch文でキャッチする。
catch文の引数にはExceptionクラスを継承したInvalidAgeExceptionクラスを指定しているのでExceptionクラスのエラー内容が変数eに入る。
例外の内容を表すメッセージはキャッチしているので「InvalidAgeException: 年齢にマイナスの値が指定されました
」と出力される。
参考記事