例外クラスの階層構造
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) {
// RuntimeExceptionとそのサブクラスのみをキャッチします
}この階層構造により、エラー処理の際に必要に応じて具体的または一般的な指定が可能になります。また、これは独自のカスタム例外を作成するための基礎となります。
チャレンジ
簡単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をスローします。- type が
ExceptionAnalyzer.java: 異なる階層レベルで例外をキャッチし、何がキャッチされたかを特定するクラスを作成します。以下の static メソッドを含めてください: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() を使用します。このチャレンジは、親の例外タイプをキャッチすると、そのすべての子もキャッチされることを示しています。これは、例外処理をどの程度具体的にするかを決定する際の重要な概念です!
チートシート
Javaの例外処理は、Throwableをルートとするクラス階層に基づいています。
Throwable
├── Error // 重大な問題(キャッチしないでください)
└── Exception // 回復可能な問題
└── RuntimeException // 非検査例外Errorは、OutOfMemoryErrorやStackOverflowErrorのような、アプリケーションが処理すべきではない重大な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() を呼び出す
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造