Menu
Coddy logo textTech

例外クラスの階層構造

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 59/87。

Javaの例外処理システムは、Throwableクラスをルートとする、適切に整理されたクラス階層に基づいて構築されています。この階層を理解することは、例外をより効果的にキャッチし、処理するのに役立ちます。

頂点に位置するのは、すべての例外とエラーの親である Throwable です。これには2つの直接のサブクラスがあります:

Throwable
├── Error          // 深刻な問題(これらをキャッチしないでください)
└── Exception      // 回復可能な問題
    └── RuntimeException  // 非チェック例外

Error は、OutOfMemoryErrorStackOverflowError のように、アプリケーションが処理を試みるべきではない深刻な問題を表します。これらは JVM 自体の根本的な問題を示しています。

Exception は、最も頻繁に扱うことになるブランチです。これは2つのカテゴリに分かれます:検査例外(Exception の直接のサブクラス)と非検査例外(RuntimeException のサブクラス)です。

// 一般的な例外クラス
Exception
├── IOException           // ファイル/ネットワークの問題
├── SQLException          // データベースの問題
└── RuntimeException
    ├── NullPointerException
    ├── ArrayIndexOutOfBoundsException
    └── IllegalArgumentException

例外はクラスであるため、継承のルールに従います。親の例外型をキャッチすると、そのすべての子の例外もキャッチされます:

try {
    // 何らかのコード
} catch (Exception e) {
    // すべての例外をキャッチします(通常は広すぎます)
}
try {
    // 何らかのコード
} catch (RuntimeException e) {
    // 実行時例外とそのサブクラスのみをキャッチします
}

この階層構造により、エラー処理において必要に応じて具体的または一般的な指定が可能になり、独自のカスタム例外を作成するための基礎となります。

challenge icon

チャレンジ

簡単

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 です)。

  • ExceptionAnalyzer.java: 異なる階層レベルで例外をキャッチし、何がキャッチされたかを特定するクラスを作成します。以下の静的メソッドを含めてください:

    analyzeSpecific(String type) - tryブロック内で ExceptionThrower.triggerRuntime(type) を呼び出します。NullPointerExceptionArrayIndexOutOfBoundsException、および 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() を呼び出す
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン