1. 導入:なぜ例外処理の理解が重要なのか
Javaの現場において、例外処理は単なる「エラー回避」以上の意味を持ちます。特にチェックされない例外であるRuntimeExceptionを正しく理解し、適切にハンドリングすることは、コードの可読性を高め、予期せぬシステムダウンを防ぐために不可欠です。本記事では、例外階層の基本から、モダンなJava開発で必須となるtry-with-resourcesやMulti-catchを組み合わせた「現場で使える」エラーハンドリング手法を解説します。
2. 基礎知識:ExceptionとErrorの階層
Javaの例外は、java.lang.Throwableを頂点とした階層構造を持っています。
・Error: JVMのメモリ不足やスタックオーバーフローなど、プログラム側では回復不可能な深刻な問題。基本的には捕捉しません。
・Exception: プログラムで制御可能な問題。
・Checked Exception (検査例外): コンパイル時に処理を強制される例外(IOExceptionなど)。
・Unchecked Exception (非検査例外 / RuntimeException): 実行時に発生する例外(NullPointerException, IllegalArgumentExceptionなど)。
実務では、ビジネスロジックの不整合やバリデーションエラーを表現するために、RuntimeExceptionを継承した「カスタム例外」を作成するのが定石です。
3. 実装/解決策:モダンな例外処理テクニック
Java 7以降で導入された「try-with-resources」と「Multi-catch」を使いこなすことで、冗長なコードを劇的に削減できます。
・try-with-resources: AutoCloseableを実装したリソースを自動的にクローズします。finallyブロックでclose処理を書く必要がなくなり、リソースリークを防げます。
・Multi-catch: 複数の例外を一行で捕捉することで、catchブロックの重複を排除し、保守性を向上させます。
4. サンプルプログラム
以下のコードは、ファイル読み込み処理を例に、実務で推奨される例外ハンドリングを実装したものです。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ExceptionHandlingSample {
public void readFile(String path) {
// try-with-resources: 処理終了後に自動でBufferedReaderをクローズ
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException | NullPointerException e) {
// Multi-catch: 関連する例外をまとめて処理
// ログ出力は実務ではLoggerを使用してください
System.err.println("リソースアクセス中にエラーが発生しました: " + e.getMessage());
} catch (Exception e) {
// 予期せぬ例外の補足
throw new RuntimeException("予期せぬシステムエラーが発生しました", e);
}
}
}
5. 応用・注意点:現場で陥りやすいバグの回避策
・例外の握りつぶしに注意: catchブロックの中で何もせず空にするのはNGです。ログ出力を行うか、上位層へ例外をラップして再スロー(Chained Exception)してください。
・RuntimeExceptionの活用: チェック例外を無理やりRuntimeExceptionでラップしてスローする手法は、フレームワークの境界や、インターフェースの制約上チェック例外を投げられない場合に非常に有効です。
・適切な粒度でcatchする: 全ての処理を大きなtryブロックで囲むのは避けましょう。例外が発生する可能性のある最小単位でスコープを区切ることで、原因特定が容易になります。
これらを意識するだけで、あなたの書くコードはより堅牢で、チームメンバーにとって読みやすいものに変わるはずです。ぜひ日々の開発に取り入れてみてください。

コメント