Javaの例外処理
この記事は一問一答問題集としても使えます。
画面左下のボタンを押すと、桃色の文字が塗りつぶされます。 (もう一度押すと元に戻ります。)
画面左下のボタンを押すと、桃色の文字が塗りつぶされます。 (もう一度押すと元に戻ります。)
例外の分類
- checked例外
- Java実行環境以外で発生する例外
- 例外処理は必須
- unchecked例外
- 実行中のプログラムが原因で発生する例外(実行時例外)や、プログラムの例外処理では復旧できない例外
- 例外処理は任意
Java実行環境以外で発生する例外
unchecked例外であり、Errorのサブクラスとして提供されている。
- AssertionError
- 文を使用している際に、 式で が返ると発生
- StackOverflowError
- アプリケーションでの再帰の回数が多すぎる場合に発生
- NoClassDefFoundError
- 読み込もうとしたクラスファイルが見つからない場合に発生
実行中のプログラムが原因で発生する例外
unchecked例外であり、RuntimeExceptionのサブクラスとして提供されている。
- ArrayIndexOutOfBoundsException
- 不正なインデックスで要素にアクセスしようとした場合に発生
- ArrayStoreException
- 不正な型のオブジェクトを配列に格納した場合に発生
- ClassCastException
- 参照変数において間違ったキャストを行った場合に発生
- IllegalStateException
- メソッドの呼び出しが正しくない状態で行われた場合に発生
- DateTimeException
- 日付/時間の計算時に誤った処理を行った場合に発生
- MissingResourceException
- リソースが見つからない場合に発生
- ArithmeticException
- 整数をゼロで除算した場合に発生
- NullPointerException
- が代入されている参照変数に対して、メソッド呼び出しを行った場合に発生
- NumberFormatException
- 整数を表さない文字列を整数に変換しようとした場合に発生
Java実行環境で発生し、例外処理では復旧できない例外
checked例外であり、 以外のExceptionのサブクラスとして提供されている。
- IOException
- 入出力を行う場合に発生
- FileNotFoundException
- ファイル入出力において、目的のファイルがなかった場合に発生
- ParserException
- 解析中に予想外のエラーがあった場合に発生
- SQLException
- データベース・アクセス時にエラーがあった場合に発生
Throwableクラス
クラス(擬似コード)
class Throwable {
void printStackTrace() {
System.out.println(エラートレース(発生場所の詳細));
}
String getMessage() {
return エラーメッセージ;
}
}
try-catch-finallyによる例外処理
- 例外が発生しそうな箇所をtryブロックで囲む
- 例外が発生したときの処理をcatchブロックの中に記述
- 例外の発生有無にかかわらず、必ず実行したい処理をfinallyブロックの中に記述
tryブロックのみの記述はコンパイルエラーになる。
スーパークラス側から記述するとコンパイルエラーになる。
ブロックは複数定義できるが、指定した例外クラスに継承関係がある場合は、SE7以降では、一つの ブロックの
()
内に複数の例外クラスを|
で区切って列記できる。
この時、- 継承関係のある例外クラスは列記できない
- キャッチした参照変数は暗黙的にfinalとなる
throwsによる例外処理
例外が発生する可能性のあるメソッドを定義する際に、発生する例外クラスを で指定しておくと、メソッド内で発生した例外オブジェクトはメソッドの呼び出し元に転送される。
の使用例
public class Main {
// OK
static void haveUncheckedException throws ArrayStoreException {
throw new ArrayStoreException();
}
// OK: unchecked例外は例外処理が任意であるため、
// 例外処理をしていなくても呼び出し元に転送される
static void haveUncheckedExceptionImplicit {
throw new ArrayStoreException();
}
// OK
static void haveCheckedException throws IOException {
throw new IOException();
}
// ERROR: checked例外では、throwsによる例外処理で転送を指示する必要がある
static void haveCheckedExceptionImplicit {
throw new IOException();
}
public static void main(String[] args) {
try {
haveUncheckedException();
haveCheckedException();
} catch (ArrayStoreException | IOException e) {
System.out.println(e);
// RESULT: java.lang.ArrayStoreException
}
}
}
独自例外クラスの作成
Exceptionクラスを継承したpublicなクラスとして定義する。
自然数(1以上の整数)でなければエラー
// 独自例外クラス
class NotNaturalNumberException extends Exception {
private int number;
public void setNumber(int number) {
this.number = number;
}
public int getNumber() {
return this.number;
}
}
public class Main {
// 自然数でなければ独自例外を発生させる
public static void isNaturalNumber(int number) throws NotNaturalNumberException {
if (number < 0) {
NotNaturalNumberException e = new NotNaturalNumberException();
e.setNumber(number);
throw e;
}
}
public static void main(String[] args) {
try {
int num = -1;
isNaturalNumber(num);
} catch (NotNaturalNumberException e) {
System.out.println("自然数ではない値を検出しました:" + e.getNumber());
}
// RESULT: 自然数ではない値を検出しました:-1
}
}
再スロー(rethrow)
- 再スロー(rethrow)
- スローされた例外を ブロックで一旦受け取り、その例外オブジェクトにエラーメッセージを追記したり、異なる例外クラスに変更したりした後、再度スローすること
class NotOddNumberException extends Exception {
NotOddNumberException() {
super("奇数ではありません");
}
}
class NotEvenNumberException extends Exception {
NotEvenNumberException() {
super("偶数ではありません");
}
}
public class Main {
public static void oddOrEven(int number) throws NotOddNumberException, NotEvenNumberException {
try {
if (number % 2 == 0) {
throw new NotOddNumberException();
} else {
throw new NotEvenNumberException();
}
} catch (Exception e) {
// 例外が起きた際に必要な処理を実装
// 処理が終わったら、例外をスロー
throw e;
}
}
public static void main(String[] args) {
try {
oddOrEven(2);
} catch (NotOddNumberException | NotEvenNumberException) {
System.out.println(e.getMessage());
// RESULT: 奇数ではありません
}
}
}
throws付メソッドのオーバーライド
class Super {
void method() throws IOException {
System.out.println("IOExceptionをスロー");
}
}
class OverrideExample1 extends Super {
// OK: 元メソッドにthrowsがあっても、オーバーライドの際にthrowsを記述しないことは可能
void method() {
System.out.println("何もスローしない");
}
}
class OverrideExample2 extends Super {
// OK: 元メソッドと同じ例外クラスをスローするのは当然OK
void method() {
System.out.println("ここでもIOExceptionをスロー");
}
}
class OverrideExample3 extends Super {
// OK: 元メソッドがスローした例外クラスのサブクラスをスローするのはOK
void method() throws FileNotFoundException {
System.out.println("IOExceptionのサブクラスをスロー");
}
}
class OverrideExample4 extends Super {
void method() throws Exception {
// ERROR: 元メソッドがスローした例外クラスのスーパークラスをスローするのはNG
System.out.println("IOExceptionのスーパークラスをスロー);
}
}
class OverrideExample5 extends Super {
// OK: RuntimeExceptionをスローするのはOK
void method() throws RuntimeException {
System.out.println("RuntimeExceptionをスロー");
}
}
class OverrideExample6 extends Super {
// OK: RuntimeExceptionのサブクラスをスローするのはOK
void method() throws NullPointerException {
System.out.println("RuntimeExceptionのサブクラスをスロー");
}
}
class OverrideExample7 extends Super {
// ERROR: RuntimeExceptionともIOExceptionとも無関係なのでNG
void method() throws SQLException {
System.out.println("その他の例外クラスをスロー");
}
}
try-with-resources
import java.sql.*;
class MyResource implements AutoCloseable {
private String name;
public MyResource(String name) {
this.name = name;
}
public void close() throws Exception {
System.out.println(name + " is closed");
}
}
public class Main {
public static void main(String[] args) {
try (MyResource obj1 = new MyResource("obj1");
MyResource obj2 = new MyResource("obj2")) {
System.out.println("tryのみでの使用が可能です");
}
// RESULT: tryのみでの使用が可能です
// obj2 is closed
// obj1 is closed
}
}
抑制された例外
import java.sql.*;
class MyResource implements AutoCloseable {
private String name;
public MyResource(String name) {
this.name = name;
}
public void method() throws SQLException {
System.out.println("ここはmethod()、この後何かが起こるかも…");
throw new SQLException("method()でエラー発生");
}
public void close() throws SQLException {
System.out.println("ここはclose()、この後何かが起こるかも…");
throw new SQLException("close()でエラー発生");
}
}
public class Main {
public static void main(String[] args) {
try (MyResource obj = new MyResource("obj")) {
obj.method();
} catch (SQLException e) {
System.out.println(e.getMessage());
System.out.println("抑制された例外を取り出します");
Throwable[] suppressedExceptions = e.getSuppressed();
System.out.println(" 抑制例外数:" + suppressedExceptions.length);
for (Throwable ex: suppressedExceptions) {
System.out.println(" " + ex.getMessage());
}
}
}
}
ここはmethod()、この後何かが起こるかも…
ここはclose()、この後何かが起こるかも…
method()でエラー発生
抑制された例外を取り出します
抑制例外数:1
close()でエラー発生
Category
隠す