CodeGym /コース /JAVA 25 SELF /高度な例外処理とベストプラクティス

高度な例外処理とベストプラクティス

JAVA 25 SELF
レベル 24 , レッスン 3
使用可能

1. 複数の catch: 異なる例外の処理

実際のプログラムでは、同じコードブロックがさまざまな種類の例外を送出することがあります。例えば、ファイルの読み取りでは FileNotFoundExceptionIOException が発生するかもしれず、データのパースでは NumberFormatException も起こり得ます。各状況を正しく処理するために、Java では複数の catch ブロックを連続して使用できます。

構文

try {
    // 危険な処理
} catch (FileNotFoundException e) {
    System.out.println("ファイルが見つかりません: " + e.getMessage());
} catch (IOException e) {
    System.out.println("入出力エラー: " + e.getMessage());
} catch (NumberFormatException e) {
    System.out.println("数値の形式が不正です: " + e.getMessage());
}

重要なポイント:
catch ブロックは、より具体的なものからより一般的なものへ並べる必要があります! 最初に catch (Exception e) と書いてしまうと、他のブロックは到達不能となり、コンパイラがエラーを出します。

なぜ重要か?

  • 特化した処理: エラーの種類ごとに異なる対応ができます(例: 別のファイルを選ばせる、再入力を促す)。
  • 可読性: どのエラーを想定し、どう処理するのかが見て取れるため、コードが理解しやすくなります。

2. 複数型をまとめた catch(マルチキャッチ)

例外の種類が異なっても、同じ処理でよい場合があります。例えば、ファイルの読み取りエラーか数値変換エラーかに関わらず、エラーメッセージを表示する、あるいはログに記録するだけでよいといったケースです。

Java 7 からは、複数の例外型を 1 つのブロックにまとめられる multi-catch(マルチキャッチ)構文が導入されました:

try {
    // 危険な処理
} catch (IOException | NumberFormatException e) {
    System.out.println("ファイルまたは数値の処理中のエラー: " + e.getMessage());
}

仕組み:

  • 縦棒(|)で例外型を並べて指定します。
  • 変数 e は最も共通な基底クラスの型(通常は Exception)として扱われます。
  • ブロック内で変数 e に別の値を代入することはできません。自動的に final とみなされます。

例:

try {
    BufferedReader reader = new BufferedReader(new FileReader("numbers.txt"));
    String line = reader.readLine();
    int number = Integer.parseInt(line);
    System.out.println("数値: " + number);
    reader.close();
} catch (IOException | NumberFormatException e) {
    System.out.println("エラー: " + e.getMessage());
}

3. 例外処理のベストプラクティス

例外を握りつぶさない

悪い例:

try {
    // 危険なことをする
} catch (Exception e) {
    // 何もしない!
}

なぜ悪いのか?
空の catch ブロックはエラーを「握りつぶし」てしまい、原因情報を失います。結果としてプログラムはデバッグ不能になります。

より良い例: 少なくともメッセージを出力するか、例外をログに記録しましょう。

catch (Exception e) {
    e.printStackTrace();
}

その場で処理できない例外は、呼び出し元へスローしましょう:

catch (IOException e) {
    throw e; // または throw new RuntimeException(e);
}

できるだけ具体的な例外を投げる

独自のメソッドや API を作る場合は、単なる ExceptionRuntimeException ではなく、できる限り具体的な例外を送出しましょう。そうすることで、コードとインターフェースは他の開発者にとって理解しやすくなります。

例:

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("残高不足です");
    }
    // ...
}

例外を制御フローの手段として使わない

例外は例外的な状況、つまり通常の実行では起きるべきでないエラーを処理するための仕組みです。通常のロジック(例えば、ループの終了や条件の判定)に使ってはいけません。

悪い例:

try {
    while (true) {
        String line = reader.readLine();
        if (line == null) break;
        // 行の処理
    }
} catch (Exception e) {
    // 例外でループを抜ける — よくない!
}

良い例:

String line;
while ((line = reader.readLine()) != null) {
    // 行の処理
}

4. 実用的な例

例: エラーの種類ごとに別々に処理する

try {
    BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
    String line = reader.readLine();
    int number = Integer.parseInt(line);
    System.out.println("数値: " + number);
    reader.close();
} catch (FileNotFoundException e) {
    System.out.println("ファイルが見つかりません!");
} catch (IOException e) {
    System.out.println("ファイル読み取りエラー!");
} catch (NumberFormatException e) {
    System.out.println("ファイル内は数値ではありません!");
}

例: 同一処理のためのマルチキャッチ

try {
    // 危険なことをする
} catch (IOException | NumberFormatException e) {
    System.out.println("エラー: " + e.getMessage());
}

5. 重要な注意点とよくある誤り

エラー No.1: catch ブロックの順序が不適切。 まずはより具体的な例外、続いて一般的な例外を書く必要があります。そうしないと、広い方のブロックに実行が到達することはありません。

エラー No.2: マルチキャッチで親子関係にある型を並べる。 例えば、catch (IOException | Exception e) はコンパイルできません。IOExceptionException のサブクラスだからです。

エラー No.3: マルチキャッチ内で変数 e を変更しようとする。 この場合、efinal と見なされるため、別の値を代入できません。

エラー No.4: 空の catch ブロック。 エラーを無視すると「サイレント」なバグにつながります。最低限、メッセージを出力するか例外をログに記録しましょう。

エラー No.5: 何でもかんでも Exception を捕まえる。 catch (Exception e) を使うと実際の問題が隠れ、デバッグが難しくなります。想定している例外だけを捕捉する方が良いです。

1
タスク
JAVA 25 SELF, レベル 24, レッスン 3
ロック未解除
財務レポート:データ問題の正確な診断
財務レポート:データ問題の正確な診断
1
タスク
JAVA 25 SELF, レベル 24, レッスン 3
ロック未解除
ゲーム設定: ロード失敗への統一的な対応
ゲーム設定: ロード失敗への統一的な対応
1
タスク
JAVA 25 SELF, レベル 24, レッスン 3
ロック未解除
機密アーカイブ:機密データへのアクセスの優先順位
機密アーカイブ:機密データへのアクセスの優先順位
1
タスク
JAVA 25 SELF, レベル 24, レッスン 3
ロック未解除
ロギングサービス: エラーを一つも失ってはなりません!
ロギングサービス: エラーを一つも失ってはなりません!
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION