はじめに
先日、Javaの例外について基礎知識をまとめたのですが、その際に「Effective Java 第3版」よりベストプラクティスをまとめた記事を発見しました。
https://masahosono.dev/posts/effective-java-3rd-edition-chapter-10
本記事ではこのサイトで簡潔にまとまっているベストプラクティスをさらに簡潔にまとめておきます。
ベストプラクティス
項目69:例外は例外的な状況でのみ使う
例外を「通常のフロー制御」に使うのはNG。
ループ処理で ArrayIndexOutOfBoundsException を使うのは典型的な悪例。
💡 ポイント: if や hasNext() などで予防できる場合は例外を使わない!
項目70:回復可能な状況にはチェック例外を使う
ユーザーの操作や外部環境(ファイル/ネットワーク)で回復可能なら チェック例外(例:IOException)。
バグやプログラミングミスは 実行時例外(例:NullPointerException)。
💡 判断基準: 呼び出し側がどうにかできるならチェック例外!
項目71:チェック例外は控えめに使う
例外が多すぎるとAPIの使い勝手が悪くなる。
対処方法が明確でないなら、実行時例外でもいい。
💡 やりがち注意: 「全部 throws Exception」は避けよう!
項目72:標準の例外を再利用する
IllegalArgumentException、IllegalStateException などを積極的に使う。
無意味な独自例外を量産しない。
例:
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
項目73:抽象化に適した例外を投げる
低レベルの例外(例:SQLException)をそのまま公開しない。
意味のある独自例外に包んで再スロー。
例:
catch (SQLException e) {
throw new DataAccessException("DB処理に失敗しました", e);
}
💡 読みやすいAPI ≒ 例外も明確
項目74:スローするすべての例外を文書化する
@throws タグでJavadocに明記。
例外の意味・発生条件・対処方法を記載。
💡 読みやすいAPI ≒ 例外も明確
項目75:例外に有益な情報を提供する
例外メッセージには「なにが」「なぜ」ダメなのかを書く。
可能なら原因のオブジェクト・値も含める。
💡 悪い例: "Error!"
💡 良い例: "無効なID: 'abc123'. 数字のみを期待していました。"
項目76:例外発生時にもオブジェクトの不変条件を保つ
処理の途中で例外が起きても、オブジェクトが壊れないように設計する。
コンストラクタやセッターでの注意が必要。
💡 ヒント: 状態変更は最後にまとめて行うのが安全。
項目77:例外を黙って握りつぶさない
catch ブロックが空 or ログだけでは危険。
原因の特定が困難になり、バグが埋もれる。
💡 最低限: ログ + 再スロー or ユーザー通知