カテゴリ: Java 更新日: 2026/04/14

JavaのChecked ExceptionとUnchecked Exceptionの違いと使い分けを徹底解説!初心者向け例外処理入門

Java Checked ExceptionとUnchecked Exceptionの違いと使い分け
Java Checked ExceptionとUnchecked Exceptionの違いと使い分け

先生と生徒の会話形式で理解しよう

生徒

「先生、Javaの例外処理を勉強していたら、Checked ExceptionとUnchecked Exceptionという言葉が出てきました。この2つは何が違うんですか?」

先生

「JavaではExceptionが2種類に分類されています。Checked Exceptionはコンパイル時にチェックされる例外で、必ず処理を書かないとコンパイルエラーになります。一方、Unchecked Exceptionは実行時に発生する例外で、処理を書かなくてもコンパイルできます。」

生徒

「どちらを使えばいいのか迷ってしまいそうです。使い分けのポイントはありますか?」

先生

「それでは、詳しく見ていきましょう!例外の種類から、具体的な使い分けまで丁寧に説明しますね。」

1. Javaの例外処理の基本とException階層

1. Javaの例外処理の基本とException階層
1. Javaの例外処理の基本とException階層

Javaの例外処理を理解するには、まず例外クラスの階層構造を知る必要があります。Javaのすべての例外はThrowableクラスを継承しています。そして、Throwableには大きく分けてErrorExceptionの2つのサブクラスが存在します。

Errorはシステムレベルの重大な問題を表し、アプリケーションでは通常処理しません。一方、Exceptionはアプリケーションで処理可能な例外を表します。このExceptionクラスがさらにChecked ExceptionとUnchecked Exceptionに分類されるのです。

Unchecked ExceptionはRuntimeExceptionクラスとそのサブクラスを指します。それ以外のExceptionクラスのサブクラスがChecked Exceptionとなります。この分類はJavaの例外処理において非常に重要な概念です。

2. Checked Exceptionとは?特徴と処理方法

2. Checked Exceptionとは?特徴と処理方法
2. Checked Exceptionとは?特徴と処理方法

Checked Exceptionは、コンパイラがチェックする例外です。この例外が発生する可能性があるメソッドを呼び出す場合、必ずtry-catchブロックで例外を捕捉するか、throws句で例外を宣言する必要があります。これを忘れるとコンパイルエラーになります。

代表的なChecked Exceptionには、IOExceptionSQLExceptionFileNotFoundExceptionClassNotFoundExceptionなどがあります。これらは主に外部リソースへのアクセスやシステムレベルの操作で発生します。

Checked Exceptionは予測可能で回復可能な例外状況を表します。例えば、ファイルが存在しない場合や、ネットワーク接続が失敗した場合など、プログラムの実行前には予測できないが、適切に処理すれば回復できる状況で使用されます。

以下は、Checked Exceptionを処理する基本的な例です。ファイルを読み込む際に発生するIOExceptiontry-catchで処理しています。


import java.io.*;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            FileReader file = new FileReader("sample.txt");
            BufferedReader reader = new BufferedReader(file);
            String line = reader.readLine();
            System.out.println("ファイルの内容: " + line);
            reader.close();
        } catch (FileNotFoundException e) {
            System.out.println("ファイルが見つかりません: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("ファイル読み込みエラー: " + e.getMessage());
        }
    }
}

このコードでは、FileReaderreadLine()メソッドがChecked ExceptionであるIOExceptionをスローする可能性があるため、try-catchブロックで囲む必要があります。もしtry-catchを書かないと、コンパイル時にエラーが発生します。

3. throws句による例外の伝播

3. throws句による例外の伝播
3. throws句による例外の伝播

Checked Exceptionを処理するもう一つの方法として、throws句を使って例外を呼び出し元に伝播させる方法があります。メソッドのシグネチャにthrowsキーワードを付けることで、そのメソッドが特定の例外をスローする可能性があることを宣言します。

この方法は、現在のメソッドでは例外を処理せず、呼び出し元に処理を委ねたい場合に使用します。例外処理を上位レイヤーで一元管理したい場合などに便利です。


import java.io.*;

public class ThrowsExample {
    // このメソッドはIOExceptionをスローする可能性があると宣言
    public static String readFile(String filename) throws IOException {
        FileReader file = new FileReader(filename);
        BufferedReader reader = new BufferedReader(file);
        String content = reader.readLine();
        reader.close();
        return content;
    }
    
    public static void main(String[] args) {
        try {
            String data = readFile("data.txt");
            System.out.println("読み込んだデータ: " + data);
        } catch (IOException e) {
            System.out.println("エラーが発生しました: " + e.getMessage());
        }
    }
}

この例では、readFileメソッドがthrows IOExceptionを宣言しているため、メソッド内で例外処理をする必要がありません。代わりに、このメソッドを呼び出すmainメソッドで例外を処理しています。

4. Unchecked Exceptionとは?特徴と発生原因

4. Unchecked Exceptionとは?特徴と発生原因
4. Unchecked Exceptionとは?特徴と発生原因

Unchecked Exceptionは、RuntimeExceptionクラスとそのサブクラスに分類される例外です。この例外はコンパイル時にチェックされないため、try-catchthrowsを記述しなくてもコンパイルが通ります。

代表的なUnchecked Exceptionには、NullPointerExceptionArrayIndexOutOfBoundsExceptionIllegalArgumentExceptionArithmeticExceptionClassCastExceptionなどがあります。これらはプログラミングのミスやロジックエラーによって発生することが多い例外です。

Unchecked Exceptionは、通常、プログラムのバグや不正な操作によって発生します。例えば、配列の範囲外にアクセスしたり、nullオブジェクトのメソッドを呼び出したりした場合です。これらはコーディング時に注意すれば防げる例外であり、実行時まで検出されません。


public class UncheckedExceptionExample {
    public static void main(String[] args) {
        // NullPointerExceptionの例
        String text = null;
        try {
            System.out.println(text.length());
        } catch (NullPointerException e) {
            System.out.println("NullPointerExceptionが発生: " + e.getMessage());
        }
        
        // ArrayIndexOutOfBoundsExceptionの例
        int[] numbers = {1, 2, 3};
        try {
            System.out.println(numbers[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("配列の範囲外アクセス: " + e.getMessage());
        }
        
        // ArithmeticExceptionの例
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println("算術エラー: " + e.getMessage());
        }
    }
}

このコードでは、3種類のUnchecked Exceptionを意図的に発生させて捕捉しています。これらの例外はtry-catchで処理していますが、書かなくてもコンパイルは通ります。ただし、実行時にプログラムが異常終了するため、重要な箇所では処理を記述することが推奨されます。

5. Checked ExceptionとUnchecked Exceptionの使い分け基準

5. Checked ExceptionとUnchecked Exceptionの使い分け基準
5. Checked ExceptionとUnchecked Exceptionの使い分け基準

Checked ExceptionとUnchecked Exceptionの使い分けは、例外が発生する原因と回復可能性によって判断します。一般的な指針として、以下のような基準があります。

Checked Exceptionは、プログラムの制御外で発生する問題に使用します。例えば、ファイルシステムやネットワーク、データベースなどの外部リソースへのアクセス時に発生する例外です。これらの問題は適切に処理すれば回復可能であり、呼び出し側に処理を強制することで、堅牢なプログラムを作成できます。

一方、Unchecked Exceptionは、プログラミングエラーやロジックの不備によって発生する問題に使用します。例えば、null参照、不正な引数、配列の範囲外アクセスなどです。これらは開発段階でバグとして修正すべき問題であり、実行時に回復することは期待されません。

また、メソッドの契約違反を示す場合もUnchecked Exceptionを使用します。例えば、メソッドに不正な引数が渡された場合はIllegalArgumentExceptionをスローします。このような例外は、メソッドの事前条件が満たされていないことを示すため、呼び出し側のバグとして扱われます。

6. 独自の例外クラスの作成方法

6. 独自の例外クラスの作成方法
6. 独自の例外クラスの作成方法

Javaでは、標準の例外クラスだけでなく、独自の例外クラスを作成することもできます。独自の例外を作成する際は、Checked ExceptionとUnchecked Exceptionのどちらにするかを決める必要があります。

Checked Exceptionとして独自の例外を作成する場合は、Exceptionクラスを継承します。Unchecked Exceptionとして作成する場合は、RuntimeExceptionクラスを継承します。この選択は、前述の使い分け基準に従って行います。


// Checked Exceptionの独自例外
class InsufficientBalanceException extends Exception {
    private double balance;
    private double withdrawAmount;
    
    public InsufficientBalanceException(double balance, double withdrawAmount) {
        super("残高不足: 残高=" + balance + ", 引き出し額=" + withdrawAmount);
        this.balance = balance;
        this.withdrawAmount = withdrawAmount;
    }
    
    public double getBalance() {
        return balance;
    }
}

// Unchecked Exceptionの独自例外
class InvalidAgeException extends RuntimeException {
    public InvalidAgeException(int age) {
        super("不正な年齢: " + age);
    }
}

public class CustomExceptionExample {
    public static void withdraw(double balance, double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException(balance, amount);
        }
        System.out.println("引き出し成功: " + amount + "円");
    }
    
    public static void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new InvalidAgeException(age);
        }
        System.out.println("年齢を設定しました: " + age + "歳");
    }
    
    public static void main(String[] args) {
        // Checked Exceptionの処理
        try {
            withdraw(5000, 10000);
        } catch (InsufficientBalanceException e) {
            System.out.println(e.getMessage());
        }
        
        // Unchecked Exceptionの処理(try-catchは任意)
        try {
            setAge(-5);
        } catch (InvalidAgeException e) {
            System.out.println(e.getMessage());
        }
    }
}

この例では、銀行の残高不足を表すInsufficientBalanceExceptionをChecked Exceptionとして、不正な年齢を表すInvalidAgeExceptionをUnchecked Exceptionとして作成しています。残高不足は外部要因で発生し回復可能な状況なのでChecked Exceptionに、年齢の不正な値はプログラミングエラーなのでUnchecked Exceptionにしています。

7. 例外処理のベストプラクティスと注意点

7. 例外処理のベストプラクティスと注意点
7. 例外処理のベストプラクティスと注意点

例外処理を適切に行うためには、いくつかのベストプラクティスに従うことが重要です。まず、例外を無視してはいけません。空のcatchブロックを書くと、エラーが発生しても気づかないため、デバッグが困難になります。

次に、例外メッセージには具体的な情報を含めるべきです。エラーが発生した原因や状況を詳しく記述することで、問題の特定が容易になります。また、例外をキャッチしたら適切にログに記録し、必要に応じて上位レイヤーに再スローすることも検討しましょう。

さらに、例外を過度に使用しないことも大切です。通常の制御フローに例外を使うと、パフォーマンスが低下し、コードが読みにくくなります。例外は本当に例外的な状況でのみ使用すべきです。

Checked Exceptionの使いすぎにも注意が必要です。すべてのメソッドに多数のChecked Exceptionを宣言すると、呼び出し側のコードが複雑になり、保守性が低下します。本当に回復可能で、呼び出し側に処理を強制すべき例外だけをChecked Exceptionにしましょう。

また、例外の型は具体的なものをキャッチするようにします。catch (Exception e)のように汎用的な例外をキャッチすると、予期しない例外まで捕捉してしまい、バグの発見が遅れる可能性があります。

8. 実践的な例外処理のパターン

8. 実践的な例外処理のパターン
8. 実践的な例外処理のパターン

実際の開発では、複数の例外を組み合わせて処理することが多くあります。例えば、データベースアクセスを伴う処理では、SQL関連の例外とネットワーク関連の例外の両方を処理する必要があります。

また、リソースの確実なクローズも重要です。Javaのtry-with-resources文を使用すると、例外が発生した場合でも確実にリソースをクローズできます。これはファイル、データベース接続、ネットワークソケットなどの処理で特に重要です。

例外の再スローも実践的なパターンの一つです。下位レイヤーで発生した例外を捕捉し、必要な処理を行った後、より適切な例外型に変換して上位レイヤーに伝えることで、アプリケーションのレイヤー構造を明確に保つことができます。

複数の例外を同時にキャッチしたい場合は、マルチキャッチ構文を使用できます。これにより、同じ処理を行う複数の例外を簡潔に記述できます。これらのパターンを理解し、状況に応じて適切に使い分けることで、堅牢で保守性の高いJavaプログラムを作成できます。

カテゴリの一覧へ
新着記事
New1
Java
Java TreeSet完全ガイド!自動ソートされるSetの特徴と使い方を徹底解説
New2
Java
JavaのHashSet使い方完全ガイド!add・remove・containsの基本から応用まで
New3
Quarkus
QuarkusでgRPCサービスを開発する完全ガイド!Java初心者でもわかる構築手順
New4
Micronaut
MicronautのDIエラーを解決する方法!NoSuchBeanと循環依存の対処法をやさしく解説
人気記事
No.1
Java&Spring記事人気No1
Java
Javaの配列とは?基本の使い方・宣言・初期化を初心者向けにわかりやすく解説
No.2
Java&Spring記事人気No2
Java
Javaの配列検索を完全攻略!値の探し方や多次元配列の条件一致を解説
No.3
Java&Spring記事人気No3
Java
Javaの型変換(キャスト)を徹底解説!暗黙的・明示的変換の違いを整理
No.4
Java&Spring記事人気No4
Micronaut
Micronautルーティングのベストプラクティス!整理しやすいURL設計を徹底解説
No.5
Java&Spring記事人気No5
Micronaut
MicronautのHTTPサーバー性能を最大化!初心者でもできるパフォーマンスチューニング
No.6
Java&Spring記事人気No6
Micronaut
MicronautでPOSTリクエストを処理する方法完全ガイド!@Bodyの使い方を初心者向けに解説
No.7
Java&Spring記事人気No7
Quarkus
QuarkusとgRPC連携ガイド!超高速なマイクロサービス開発の始め方
No.8
Java&Spring記事人気No8
Micronaut
MicronautでFormデータを受け取る方法完全ガイド!フォーム処理の基礎を初心者向けに解説