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) {
    // RuntimeExceptionとそのサブクラスのみをキャッチします
}

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

challenge icon

チャレンジ

簡単

Javaの例外階層が実際にどのように機能するかを示す例外アナライザーを構築しましょう!特定のレベルで例外をキャッチし、どのタイプがキャッチされたかを報告するシステムを作成します。

コードは3つのファイルに分けて構成します:

  • ExceptionThrower.java: 入力に基づいて異なるタイプの例外を発生させることができるクラスを作成します。このクラスには3つの static メソッドが必要です:

    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" を持つ RuntimeException をスローします。

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

    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() を使用します。このチャレンジは、親の例外タイプをキャッチすると、そのすべての子もキャッチされることを示しています。これは、例外処理をどの程度具体的にするかを決定する際の重要な概念です!

チートシート

Javaの例外処理は、Throwableをルートとするクラス階層に基づいています。

Throwable
├── Error          // 重大な問題(キャッチしないでください)
└── Exception      // 回復可能な問題
    └── RuntimeException  // 非検査例外

Errorは、OutOfMemoryErrorStackOverflowErrorのような、アプリケーションが処理すべきではない重大なJVMの問題を表します。

Exceptionは、検査例外(直接のサブクラス)と非検査例外(RuntimeExceptionのサブクラス)に分かれます:

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

親の例外型をキャッチすると、そのすべての子クラスもキャッチされます:

try {
    // 何らかのコード
} catch (Exception e) {
    // すべての例外をキャッチします
}

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

例外のクラス名を取得するには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腕試し

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

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