1. クラス Throwable: すべての例外の祖先
ここでは、Java の例外システムの仕組みを詳しく見ていきます。Throwable とは何か、Exception と Error の違い、そして「検査例外」と「非検査例外」とは何か。これは、プログラムで適切にエラー処理を行うための基礎です。
Java ではすべての例外とエラーは、java.lang.Throwable クラスを継承するオブジェクトです。
Throwable は、Java における問題処理の階層全体の祖となる存在です。
概略:
Throwable
├── Exception
└── Error
Throwable は、Java で「throw」でき「catch」できるすべてのものの基底クラスです。直接使用するものではなく、より具体的なエラー型のための土台として機能します。
Exception — 「通常の」エラー向け
Exception は、プログラム内で発生しうる、そして処理すべき例外の基底クラスです。これは「業務的な」エラーで、ファイル、ネットワーク、入出力、ユーザーの操作ミスなどに起因します。多くの try-catch は Exception のサブクラスを扱うことになります。
例:
- IOException — ファイルまたはネットワークの操作時のエラー。
- SQLException — データベース操作時のエラー。
- FileNotFoundException — ファイルが見つからない。
Error — JVM の致命的エラー用
Error は、Java 仮想マシン(JVM)レベルで発生するエラーの基底クラスです。通常、これはアプリケーションが処理できず、また処理すべきでもない深刻な障害です。Error が発生した場合、アプリケーションは継続実行できない可能性が高いです。
例:
- OutOfMemoryError — メモリ不足。
- StackOverflowError — スタックオーバーフロー(たとえば無限再帰による)。
- NoClassDefFoundError — 必要なクラスが見つからない。
重要:
Error を捕捉・処理するのは、ほとんどの場合悪手です。これはあなたのプログラムの不具合ではなく、実行環境の障害です。
2. Checked vs Unchecked exceptions: それは何か?
Java の例外は大きく 2 つのグループに分かれます。
検査例外(Checked exceptions)
これは? コンパイラが処理するか、明示的にスローすることを強制する例外。
いつ発生する? 通常、外部リソースに関係します(ファイル、ネットワーク、データベース、ユーザー入力)。
どう扱う? コードを try-catch で囲むか、メソッドのシグネチャに throws を追加します。
例: IOException, SQLException, FileNotFoundException
例:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // IOException を投げる可能性がある
// ...
}
処理またはスローを行わない場合、プログラムはコンパイルできません。
非検査例外(Unchecked exceptions)
これは? コンパイラが必須の処理を要求しない例外。
いつ発生する? 通常はプログラムのロジックの誤り(ゼロ除算、配列の範囲外アクセス、null 参照など)。
どう扱う? 捕捉してもかまいませんが必須ではありません。検証によって未然に防ぐのが望ましいです。
階層上の位置は? すべて RuntimeException を継承します。
例: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException
例:
int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
コンパイラはこの例外の捕捉を強制しませんが、発生するとプログラムはクラッシュします。
3. 階層を 1 枚の図で
graph TD
Throwable --> Error
Throwable --> Exception
Exception --> RuntimeException
Exception --> CheckedExceptions["(その他の Checked Exceptions)"]
Error --> OutOfMemoryError
Error --> StackOverflowError
RuntimeException --> NullPointerException
RuntimeException --> IndexOutOfBoundsException
RuntimeException --> IllegalArgumentException
%% スタイル
style Throwable fill:#ffa64d,color:#000
style Exception fill:#ffa64d,color:#000
style CheckedExceptions fill:#ffa64d,color:#000
style Error fill:#ff4d4d,color:#fff
style OutOfMemoryError fill:#ff4d4d,color:#fff
style StackOverflowError fill:#ff4d4d,color:#fff
style RuntimeException fill:#4dff88,color:#000
style NullPointerException fill:#4dff88,color:#000
style IndexOutOfBoundsException fill:#4dff88,color:#000
style IllegalArgumentException fill:#4dff88,color:#000
表: 主な相違点
| グループ | 親クラス | 処理が必須か? | 例 |
|---|---|---|---|
| Checked Exception | |
はい | |
| Unchecked | |
いいえ | |
| Error | |
いいえ | |
4. コードではどう見える?
Checked Exception: ファイルの例
import java.io.*;
public class FileDemo {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("nofile.txt"); // FileNotFoundException (checked)
int data = reader.read();
System.out.println(data);
reader.close();
} catch (IOException e) {
System.out.println("ファイル処理中のエラー: " + e.getMessage());
}
}
}
コンパイラは IOException の処理を要求します!
Unchecked Exception: ゼロ除算の例
public class ExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0;
int c = a / b; // ArithmeticException (unchecked)
System.out.println("結果: " + c);
}
}
コンパイラは処理を要求しませんが、プログラムはクラッシュします。
5. なぜ例外の階層が必要か?
- 柔軟な処理: 特定のエラー(FileNotFoundException)だけでなく、グループ全体(IOException や Exception)も捕捉できます。
- コードの再利用: 同種のエラーを一元的に処理できます。
- コードの明瞭性: 主要なロジックが細かな検証コードで散らからずに済みます。
例:
try {
// 危険なコード
} catch (FileNotFoundException e) {
System.out.println("ファイルが見つかりません!");
} catch (IOException e) {
System.out.println("入出力エラー!");
} catch (Exception e) {
System.out.println("問題が発生しました: " + e.getMessage());
}
6. 例外処理でよくある誤り
誤り № 1: 例外の無視。 catch (Exception e) {} と書くのはよくありません。エラー原因の情報を失います。
誤り № 2: 捕捉しすぎ。 catch (Exception e) は予期しないものまで何でも捕捉します。自分が適切に処理できる例外だけを捕捉しましょう。
誤り № 3: Error を捕捉する。 低レベルコードを書いていない限り、Error を捕捉すべきではありません。これは JVM の問題であり、あなたのプログラムの問題ではありません。
誤り № 4: checked と unchecked を区別しない。 すべての例外が同じではありません! checked は処理が必須(Exception)、unchecked は必須ではありません(RuntimeException とそのサブクラス)。
誤り № 5: 例外に情報を追加しない。 独自の例外を作成する場合は、必ず情報量のあるメッセージを付与しましょう。
GO TO FULL VERSION