例外処理

例外処理により、プログラムはより堅牢になります。このレッスンでは、Javaの例外処理メカニズムを学びます。

例外とは

例外はプログラムの実行中に発生するエラーです。

例外の分類

TEXT
Throwable
├── Error(重大なエラー、プログラムは処理できない)
│   ├── OutOfMemoryError
│   └── StackOverflowError
└── Exception(例外、プログラムは処理可能)
    ├── チェック例外(処理必須)
    │   ├── IOException
    │   └── SQLException
    └── 非チェック例外(RuntimeException)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        └── NumberFormatException
▶ 試してみよう

try-catch

構文

JAVA
try {
    // 例外をスローする可能性のあるコード
} catch (例外型 変数名) {
    // 例外を処理
}

例:基本的な例外処理

JAVA
public class TryCatchDemo {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("算術エラー: " + e.getMessage());
        }
        System.out.println("プログラムは続行されます");
    }
}
▶ 試してみよう

出力:

TEXT
算術エラー: / by zero
プログラムは続行されます

複数のcatchブロック

JAVA
try {
    // 複数の例外をスローする可能性のあるコード
} catch (例外型1 e1) {
    // 例外1を処理
} catch (例外型2 e2) {
    // 例外2を処理
} catch (Exception e) {
    // その他の例外を処理
}

例:複数のcatch

JAVA
public class MultiCatch {
    public static void main(String[] args) {
        try {
            String s = "abc";
            int num = Integer.parseInt(s);
            int result = 10 / num;
        } catch (NumberFormatException e) {
            System.out.println("数値形式エラー: " + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("算術エラー: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("その他のエラー: " + e.getMessage());
        }
    }
}
▶ 試してみよう

try-catch-finally

finallyブロックは例外が発生しても発生しなくても、常に実行されます。

構文

JAVA
try {
    // 例外をスローする可能性のあるコード
} catch (例外型 e) {
    // 例外を処理
} finally {
    // 常に実行
}

例:finally

JAVA
public class FinallyDemo {
    public static void main(String[] args) {
        try {
            System.out.println("tryブロック");
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println("catchブロック");
        } finally {
            System.out.println("finallyブロック");
        }
    }
}
▶ 試してみよう

出力:

TEXT
tryブロック
catchブロック
finallyブロック

例:リソース解放

JAVA
import java.io.*;

public class ResourceDemo {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("test.txt");
            // ファイルを読み取る
        } catch (FileNotFoundException e) {
            System.out.println("ファイルが見つかりません");
        } finally {
            // リソースを解放
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
▶ 試してみよう

try-with-resources

Java 7で導入され、リソースを自動的に閉じます。

構文

JAVA
try (リソース型 変数 = new リソース()) {
    // リソースを使用
} catch (例外型 e) {
    // 例外を処理
}

例:try-with-resources

JAVA
import java.io.*;

public class TryWithResources {
    public static void main(String[] args) {
        // リソースを自動的に閉じる
        try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
            String line = reader.readLine();
            System.out.println(line);
        } catch (IOException e) {
            System.out.println("読み取りエラー: " + e.getMessage());
        }
        // readerは自動的に閉じられ、finallyは不要
    }
}
▶ 試してみよう

throwとthrows

throw:例外をスロー

JAVA
public static int divide(int a, int b) {
    if (b == 0) {
        throw new ArithmeticException("ゼロで割ることはできません");
    }
    return a / b;
}

throws:例外を宣言

JAVA
public static void readFile(String path) throws FileNotFoundException {
    FileReader reader = new FileReader(path);
}

例:throwとthrows

JAVA
public class ThrowDemo {
    public static int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("ゼロで割ることはできません");
        }
        return a / b;
    }
    
    public static void validateAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("無効な年齢: " + age);
        }
    }
    
    public static void main(String[] args) {
        try {
            System.out.println(divide(10, 0));
        } catch (ArithmeticException e) {
            System.out.println(e.getMessage());  // ゼロで割ることはできません
        }
        
        try {
            validateAge(-5);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());  // 無効な年齢: -5
        }
    }
}
▶ 試してみよう

カスタム例外

手順

  1. ExceptionまたはRuntimeExceptionを継承
  2. コンストラクタを提供

例:カスタム例外

JAVA
// カスタム例外クラス
public class InsufficientBalanceException extends Exception {
    private double balance;
    private double amount;
    
    public InsufficientBalanceException(double balance, double amount) {
        super("残高不足: " + balance + ", 引出: " + amount);
        this.balance = balance;
        this.amount = amount;
    }
    
    public double getBalance() {
        return balance;
    }
    
    public double getAmount() {
        return amount;
    }
}

// カスタム例外の使用
public class BankAccount {
    private double balance;
    
    public BankAccount(double balance) {
        this.balance = balance;
    }
    
    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException(balance, amount);
        }
        balance -= amount;
        System.out.println("引出成功、残高: " + balance);
    }
    
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);
        
        try {
            account.withdraw(500);   // 引出成功、残高: 500.0
            account.withdraw(800);   // 例外をスロー
        } catch (InsufficientBalanceException e) {
            System.out.println(e.getMessage());
            System.out.println("残高: " + e.getBalance());
            System.out.println("引出: " + e.getAmount());
        }
    }
}
▶ 試してみよう

一般的な例外

例外 説明 原因
NullPointerException ヌルポインタ nullオブジェクトでメソッドを呼び出す
ArrayIndexOutOfBoundsException 配列インデックス範囲外 存在しないインデックスにアクセス
NumberFormatException 数値形式エラー 文字列から数値への変換に失敗
ClassCastException クラスキャストエラー ダウンキャストの型不一致
ArithmeticException 算術エラー ゼロで割る
FileNotFoundException ファイルが見つからない ファイルパスが間違っている
IOException IOエラー ファイルの読み書きに失敗

例外処理の原則

原則 説明
具体的な例外を最初に 一般的な例外の前に具体的な例外をキャッチ
例外を無視しない 少なくともログに記録
finallyでリソース解放 またはtry-with-resourcesを使用
例外をフロー制御に使用しない 例外はエラー用、フロー制御用ではない

❓ よくある質問

Q ErrorとExceptionの違いは何ですか?
A Errorはプログラムが処理できない重大な問題です。Exceptionはプログラムがキャッチして処理できる問題です。
Q チェック例外と非チェック例外の違いは何ですか?
A チェック例外は処理必須(try-catchまたはthrows)。非チェック例外は処理不要です。
Q 什么时候カスタム例外を作成すべきですか?
A 残高不足やユーザーが見つからないなど、ビジネス例外のタイプを区別する必要がある場合。

📖 まとめ

📝 演習

  1. 例外処理: ファイルを読み取るメソッドを作成し、ファイルが見つからない場合と読み取りエラーを処理
  2. カスタム例外: 年齢バリデーションのためのAgeOutOfBoundsExceptionを定義
  3. リソース管理: try-with-resourcesを使用してファイルコピーを実装

次のレッスン

次のレッスンでは、実践:OOPを学びます — オブジェクト指向知識を適用します。

100%