Javaで業務システム開発を行っていると、例外設計の方針によってコード品質が大きく変わる場面に何度も遭遇します。
特に「checked例外とunchecked例外をどう使い分けるか」は、保守性・可読性・障害対応速度に直結します。
実務では「とりあえずthrows Exception」や「全部RuntimeException」にしてしまうケースも見かけますが、この設計は後から確実に問題になります。
結論として、例外は「呼び出し側が回復可能かどうか」で判断するのが最も実践的です。
本記事では、現場で迷わないための判断基準を整理します。
checked例外とunchecked例外とは
Javaの例外は大きく次の2種類に分類されます。
| 種類 | 継承元 | 特徴 |
|---|---|---|
| checked例外 | Exception | コンパイル時に処理を強制される |
| unchecked例外 | RuntimeException | 処理は任意(強制されない) |
Javaの例外階層は次の構造になっています。
Throwable
├ Error
└ Exception
├ RuntimeException(unchecked)
└ その他(checked)
つまり、RuntimeExceptionを継承しているかどうかが判定基準です。
checked例外の特徴
checked例外は、コンパイル時に必ず処理を求められます。
代表例
- IOException
- SQLException
- ClassNotFoundException
- ParseException
例
|
1 2 3 |
public void readFile() throws IOException { FileReader reader = new FileReader("test.txt"); } |
呼び出し側は必ず以下のどちらかを行う必要があります。
|
1 2 3 4 5 |
try { readFile(); } catch (IOException e) { e.printStackTrace(); } |
または
|
1 |
public void execute() throws IOException |
checked例外の目的
checked例外は以下を保証します。
- 想定される失敗を無視させない
- 呼び出し側に対応責任を持たせる
- 回復処理を実装させる
unchecked例外の特徴
unchecked例外はRuntimeExceptionを継承した例外です。
代表例
- NullPointerException
- IllegalArgumentException
- IllegalStateException
- IndexOutOfBoundsException
例
|
1 2 3 4 5 |
public void setAge(int age) { if (age < 0) { throw new IllegalArgumentException("age must be positive"); } } |
try-catchは必須ではありません。
checked例外とunchecked例外の本質的な違い

最も重要なのはここです。
| 観点 | checked例外 | unchecked例外 |
|---|---|---|
| コンパイルチェック | あり | なし |
| 回復可能性 | 高い | 低い |
| 想定対象 | 外部要因 | プログラムミス |
| 呼び出し側責任 | あり | 基本なし |
| 主な用途 | IO・通信・DB | バグ・不正状態 |
使い分けの判断基準(実務向け)
現場では次の基準で判断すると迷いません。
判断ルール
✅ 呼び出し側で復旧できる → checked例外
✅ プログラムの誤り → unchecked例外
checked例外にすべきケース
外部要因による失敗
- ファイルが存在しない
- ネットワーク切断
- DB接続失敗
- API通信エラー
例:
SQLException
IOException
これらは再試行や代替処理が可能です。
unchecked例外にすべきケース
プログラム設計ミス
- nullを渡した
- 不正な引数
- 状態遷移ミス
- 初期化漏れ
例:
|
1 |
throw new IllegalStateException("service not initialized"); |
修正対象は呼び出し側ではなく開発者です。
よくある間違った設計
Exceptionをそのまま投げる
throws Exception
問題点:
- 例外の意味が消える
- ハンドリング不能
- API仕様が不明確
実務では避けるべき設計です。
checked例外の多用
checked例外を増やしすぎると次の問題が発生します。
- try-catch地獄
- 可読性低下
- 例外握りつぶし
結果として以下が増えます。
catch (Exception e) {}
これは最悪のアンチパターンです。
独自例外クラスの設計指針
業務開発では独自例外を作成します。
checked例外
|
1 2 3 4 5 |
public class BusinessException extends Exception { public BusinessException(String message) { super(message); } } |
業務ルール違反など。
unchecked例外
|
1 2 3 4 5 |
public class SystemException extends RuntimeException { public SystemException(String message) { super(message); } } |
システム異常・設計ミス。
レイヤー別の例外設計(重要)
実務では層ごとに役割を分けます。
| レイヤー | 推奨例外 |
|---|---|
| Controller | unchecked |
| Service | checked / 独自例外 |
| Repository | checked |
| Framework境界 | unchecked変換 |
例外変換パターン
|
1 2 3 4 5 |
try { repository.save(); } catch (SQLException e) { throw new SystemException(e); } |
低レイヤー依存を隠蔽できます。
checked例外をuncheckedへ変換する理由
理由は主に3つあります。
- API汚染を防ぐ
- 依存技術を隠す
- 上位層をシンプルにする
SpringがRuntimeException中心なのもこの思想です。
よくある質問(Q & A)
- checked例外は不要と言われるのはなぜですか?
-
過剰に使用するとtry-catchが増え、例外処理が形式化してしまうためです。現代フレームワークではunchecked例外中心の設計が増えています。
- RuntimeExceptionだけで統一しても問題ありませんか?
-
小規模開発では可能ですが、大規模開発では回復可能な障害を区別できなくなります。外部I/Oはchecked例外を使用する方が安全です。
- 業務例外はどちらにすべきですか?
-
ユーザー操作で回復可能な場合はchecked例外、設計不整合や状態異常はunchecked例外が適切です。
まとめ
checked例外とunchecked例外の使い分けは、Java設計における重要な判断ポイントです。
判断基準は非常にシンプルです。
- 回復可能な問題 → checked例外
- プログラムの誤り → unchecked例外
例外は「エラー通知」ではなく「責任の所在」を表現する仕組みです。
適切に設計することで、保守性・障害解析・拡張性が大きく向上します。

