結論: Java の例外はすべて Throwable のサブクラスで、その下が Error(回復を想定しない深刻な問題)と Exception(プログラムで対処しうる問題)に分かれます。Exception のうち RuntimeException とそのサブクラスは「非検査例外」、それ以外の Exception のサブクラスは「検査例外」です。検査例外は catch するか throws で宣言しないとコンパイルエラーになり、Error と RuntimeException 系はどちらも不要です。
継承の繋がり
ThrowableError(非検査)VirtualMachineErrorOutOfMemoryErrorStackOverflowError
ExceptionRuntimeException(非検査)NullPointerExceptionIllegalArgumentExceptionArithmeticExceptionIndexOutOfBoundsExceptionClassCastException
- 検査例外(
RuntimeException以外のExceptionのサブクラス)IOExceptionSQLExceptionReflectiveOperationExceptionClassNotFoundException
途中の親クラスは代表的なものだけ載せています。
上の「検査例外」は分類名で、そういう名前のクラスがあるわけではありません。IOException などは Exception の(直接または間接の)サブクラスです。なお Throwable 自身と Exception 自身も検査例外として扱われます。
検査例外と非検査例外の違い
| 種類 | 該当するクラス | catch か throws が必須か |
典型的な原因 |
|---|---|---|---|
| 検査例外 | Exception のサブクラスのうち RuntimeException 系以外 |
必須(ないとコンパイルエラー) | ファイル・DB・ネットワークなど外部要因 |
| 非検査例外 | RuntimeException とそのサブクラス |
不要 | null 参照、範囲外の添字など、プログラムの誤り |
| エラー(非検査) | Error とそのサブクラス |
不要 | メモリ不足、スタックの使い切りなど JVM 側の問題 |
コード例
// 検査例外: catch するか throws で宣言しないとコンパイルエラー
String readFirstLine(Path path) throws IOException {
return Files.readAllLines(path).get(0);
}
// 非検査例外: 宣言しなくてもコンパイルは通る(実行時に発生しうる)
int divide(int a, int b) {
return a / b; // b が 0 なら ArithmeticException
}
原理(なぜそうなるか)
検査例外は、プログラムが正しくても外部の状況(ファイルがない、接続が切れた等)によって起こりうる失敗です。呼び出し側が対処を考える必要があるため、Java はコンパイル時に catch か throws のどちらかを書くことを強制します。
RuntimeException 系は、null チェックの漏れや添字の範囲外など、コードを直せば防げる誤りです。これらはほぼどの行でも起こりうるので、すべてに宣言を強制すると実用になりません。そのため宣言は任意です。Error は JVM の資源不足など、アプリケーションが通常は回復できない状況を表すため、こちらも宣言を求めません。
catch (Exception e) は RuntimeException 系も含めて捕まえます。catch は上から順に照合されるので、サブクラスの catch を親クラスの catch より先に書きます(逆に書くと、サブクラスは捕捉済みとしてコンパイルエラーになります)。
(この初版はAIが作成。随時書き換え)