例外クラスの階層構造
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 59/87。
Javaの例外処理システムは、Throwableクラスをルートとする、適切に整理されたクラス階層に基づいて構築されています。この階層を理解することは、例外をより効果的にキャッチし、処理するのに役立ちます。
頂点に位置するのは、すべての例外とエラーの親である Throwable です。これには2つの直接のサブクラスがあります:
Throwable
├── Error // 深刻な問題(これらをキャッチしないでください)
└── Exception // 回復可能な問題
└── RuntimeException // 非チェック例外Error は、OutOfMemoryError や StackOverflowError のように、アプリケーションが処理を試みるべきではない深刻な問題を表します。これらは JVM 自体の根本的な問題を示しています。
Exception は、最も頻繁に扱うことになるブランチです。これは2つのカテゴリに分かれます:検査例外(Exception の直接のサブクラス)と非検査例外(RuntimeException のサブクラス)です。
// 一般的な例外クラス
Exception
├── IOException // ファイル/ネットワークの問題
├── SQLException // データベースの問題
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentException例外はクラスであるため、継承のルールに従います。親の例外型をキャッチすると、そのすべての子の例外もキャッチされます:
try {
// 何らかのコード
} catch (Exception e) {
// すべての例外をキャッチします(通常は広すぎます)
}try {
// 何らかのコード
} catch (RuntimeException e) {
// 実行時例外とそのサブクラスのみをキャッチします
}この階層構造により、エラー処理において必要に応じて具体的または一般的な指定が可能になり、独自のカスタム例外を作成するための基礎となります。
チャレンジ
簡単Javaの例外階層が実際にどのように機能するかを示す例外アナライザーを構築しましょう!例外を異なる具体性のレベルでキャッチし、どのタイプがキャッチされたかを報告するシステムを作成します。
コードは3つのファイルに分けて構成します:
ExceptionThrower.java: 入力に基づいて異なるタイプの例外を発生させることができるクラスを作成します。クラスには3つの静的メソッドを含める必要があります:triggerRuntime(String type)- type文字列に基づいて、異なる実行時例外をスローします:- typeが
"null"の場合、メッセージ"Null value encountered"を持つNullPointerExceptionをスローします。 - typeが
"index"の場合、メッセージ"Invalid index"を持つArrayIndexOutOfBoundsExceptionをスローします。 - typeが
"argument"の場合、メッセージ"Bad argument"を持つIllegalArgumentExceptionをスローします。
triggerArithmetic()- メッセージ"Division error"を持つArithmeticExceptionをスローします。triggerGeneric()- メッセージ"Generic runtime error"を持つIllegalStateExceptionをスローします(その階層は Exception > RuntimeException > IllegalStateException です)。- typeが
ExceptionAnalyzer.java: 異なる階層レベルで例外をキャッチし、何がキャッチされたかを特定するクラスを作成します。以下の静的メソッドを含めてください:analyzeSpecific(String type)- tryブロック内でExceptionThrower.triggerRuntime(type)を呼び出します。NullPointerException、ArrayIndexOutOfBoundsException、およびIllegalArgumentExceptionに対して個別のcatchブロックを使用します。それぞれについて、Caught specific: [exception class simple name]に続いてMessage: [exception message]と出力します。analyzeWithParent()- tryブロック内でExceptionThrower.triggerArithmetic()を呼び出します。親タイプであるRuntimeExceptionを使用してキャッチします。Caught via parent: RuntimeExceptionに続いてActual type: [exception class simple name]と出力します。analyzeWithGrandparent()- tryブロック内でExceptionThrower.triggerGeneric()を呼び出します。さらに上位の階層であるExceptionを使用してキャッチします。Caught via grandparent: Exceptionに続いてActual type: [exception class simple name]と出力します。Main.java: 例外アナライザーをまとめます!1つの入力として、例外タイプの文字列("null"、"index"、または"argument"のいずれか)を受け取ります。まず、
=== Specific Catch ===と出力し、入力引数を使用してanalyzeSpecificを呼び出します。次に空行を出力し、
=== Parent Catch ===と出力してからanalyzeWithParentを呼び出します。最後に空行を出力し、
=== Grandparent Catch ===と出力してからanalyzeWithGrandparentを呼び出します。
1つの入力を受け取ります:発生させる例外のタイプ("null"、"index"、または "argument")。
例外のクラス名を取得するには e.getClass().getSimpleName() を使用し、メッセージを取得するには e.getMessage() を使用します。このチャレンジは、親の例外タイプをキャッチすると、そのすべての子もキャッチされることを示しています。これは、例外処理をどの程度具体的にするかを決定する際の重要な概念です!
自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String type = scanner.nextLine();
// TODO: "=== Specific Catch ===" を出力し、ExceptionAnalyzer.analyzeSpecific(type) を呼び出す
// TODO: 空行を出力し、次に "=== Parent Catch ===" を出力してから、ExceptionAnalyzer.analyzeWithParent() を呼び出す
// TODO: 空行を出力し、次に "=== Grandparent Catch ===" を出力してから、ExceptionAnalyzer.analyzeWithGrandparent() を呼び出す
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造