0. 始めに
例によって、Javaの例外が分かっていなかったので、まとめてみた。
今回は(こそ?)自分用メモとして記事を書く。
1. 例外処理とは?
例外の定義も色々あったので、参考1 p.264 から引用したところ、
Javaにおけるプログラムの実行中に発生するトラブルには、大きく分けて2つの種類があります。
実行環境のトラブルなど、プログラムからは対処しようのない事態を表すエラーと、プログラムが対処できる例外の2つです。例外はさらに、検査例外と非検査例外に分かれます。検査例外とは、例外処理を記述したかをコンパイラが検査する例外を指します。
もう一方の非検査例外は、例外処理を記述したかどうかをコンパイラが検査しない例外を指します。
とのこと。要するに3つに分けられる。
さらにそれぞれの例外に応じた例外クラスが存在し、その関係は下記の通り。
(サブクラスも載せたい)
2. 各例外の基本
①検査例外
検査例外のクラスであるExceptionを継承している例外クラスは、try-catchやthrows句で宣言するなどの処理が必須になる。
ここで言う検査とは、catchやthrowのこと。検査例外を検査していない場合はコンパイルエラーになる。
②非検査例外
Exceptionのサブクラスでも、RuntimeExceptionを継承していれば非検査例外として扱われ、try-catchなどの処理は不要になる。
もちろん、例外処理を記載しても問題ない。
③エラー
メモリ不足やファイルの読み込みに失敗したなどの例外。非検査例外と同じく、例外処理とかしなくていい。
3. 例外処理書き方あれこれ
3.1 標準的な書き方
①Exceptionをキャッチする
明示的に例外をスローするときは、throw
を付ける(検査例外のみ?検証する)
catch
ブロックのパラメータはThrowable
なので、全ての例外をキャッチできる。
try { // 例外が発生するかもしれない処理をくくる
throw new Exception();
} catch (Exception e) {
... // try 中で例外が発生した時に処理される
} finally {
// 例外が発生してもしなくても実行される
}
②Exceptionをスローする メソッド宣言にthrowsを使う。
private void hogehoge() throws Exception {
throw new Exception();
}
3.2 マルチキャッチ
キャッチする例外クラスを複数指定できる。参考2より引用させていただきました。
// Java6以前の場合
try {
. . .
} catch (IOException ex) {
logger.log(ex);
throw ex;
} catch (SQLException ex) {
logger.log(ex);
throw ex;
}
// Java7以降の場合
try {
. . .
} catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
3.3 検査例外のスローを記載したら、絶対にキャッチも書く
検査例外をスロー宣言しているメソッドは、キャッチするか再スローしないとコンパイルエラーになる。。。
public void method() throws Exception {}
// case1
try {
method();
} catch (Exception e) { // catchが無いとエラー
...
}
// case 2
public void method2() throws Exception { // 再スローしないとエラー
method();
}
4. 例外発生後の挙動
4.1 for文中で例外が発生したら、それ以降のループ処理はされない
参考1 p.349より引用。
i = 1
の時にStirngIndexOutOfboundsException
が発生するので、i > 1
のループ処理は実行されない。
String[] array = {"abcde", "fgh", "ijk"};
String[] array2 = new String[3];
int i = 0;
try {
for (String s: array) {
array2[i] = s.substring(1, 4);
i++;
}
} catch (Exception e) {
System.out.println("Error");
}
for (String s: array2) {
System.out.println(s);
}
// 実行結果
// Error エラーをキャッチしたことによる出力
// bcd array2[0]
// null array2[1]
// null array2[2]
4.2 例外をスローしているメソッドをオーバーライドする時の注意
例外をスローしているメソッドをオーバーライドした場合、そのメソッドには以下の制約が追加される(参考3 p. 299を元に一部表現を変えて引用)。
①サブクラスのメソッドでスローできる例外は、スーパークラスのメソッドがスローする例外と同じかそのサブクラスの例外
②スーパークラスのメソッドがどんな例外をスローしていようと、サブクラスのメソッドではRuntimeException
かそのサブクラスの例外としてスロー出来る(実行時例外に倒せる)
③そもそも、スーパークラスのメソッドが例外をスローしているからと言って、サブクラスのメソッドでスローするのが必須ではない
具体例を出す(参考3 p.300より引用)。ここで、NG:コンパイルエラーとする。
class Super { void method() throws IOException {} }
class SubA { void method() } // OK 例外をスローしなくても良い
class SubB { void method() throws FileNotFoundException {} } // OK IOExceptionのサブクラスでスローしている
class SubC { void method() throws Exception {} } // NG IOExceptionのスーパークラスでスローしている
class SubD { void method() throws ClassNotFoundException {} } // NG IOExceptionと継承関係にない例外クラスでスローしている
class SubE { void method() throws RuntimeException {} } // OK 実行時例外に倒している
5. 参考
1.志賀澄人 (2019) 「徹底攻略 Java SE 8 Silver 問題集 [1Z0-808] 対応」 ㈱インプレス 発行
2.【社内勉強会】Javaの例外処理(2017/04/26)
3.山本道子 (2015) Java プログラマ Silver SE 7(第5刷発行) ㈱翔泳社 発行