Java | 安全設計ベストプラクティス:returnで抜ける vs 例外を投げる

Java Java
スポンサーリンク

実務では「return で抜けるべきか」「throw(例外)で止めるべきか」は非常に重要な設計判断ポイントです。
ここでは、安全設計ベストプラクティスとして、初心者でも理解できるように図+コード+判断基準表で整理します。


1. 全体イメージ図:処理の抜け方

+-------------------------------+
| 処理フロー                     |
|-------------------------------|
| ① 通常終了 → return          |
| ② 条件分岐で早期return         |
| ③ 予期しない異常 → throw      |
|-------------------------------|
| return = 正常な抜け道          |
| throw  = 異常な抜け道          |
+-------------------------------+

2. 使い分けの基本方針表

分類状況ベストプラクティス理由
✅ 正常終了計算・処理が終わったreturn 値正常なフローの終端。呼び出し元が続行できる。
⚠️ 条件不一致想定済み・異常ではないreturn(早期return)想定内なので例外を使わずシンプルに抜ける。
❌ 異常終了想定外エラー・入力不正throw new XxxException()呼び出し元に異常を伝える。ログ出力・上位でハンドル。
🚫 致命的エラー回復不能(DB停止・設定欠落)throw + ログ + fail-fast続行しても危険。即停止+明示的な例外が安全。

3. コード比較(例題:ユーザー登録処理)

❌ NG例:全部 return で逃げる(異常も含む)

public boolean register(User user) {
    if (user == null) {
        return false; // ← 何が起きたかわからない
    }
    if (user.getName().isEmpty()) {
        return false; // ← ログもなし
    }
    // DB登録...
    return true;
}
Java

問題点:

  • 呼び出し元からは「false」しかわからず、原因不明。
  • デバッグ・監視が困難。

✅ OK例:想定外は例外で伝える、安全設計版

public boolean register(User user) {
    if (user == null) {
        throw new IllegalArgumentException("user is null");
    }
    if (user.getName().isEmpty()) {
        throw new ValidationException("名前が未入力です");
    }

    try {
        userRepository.save(user);
        return true;
    } catch (SQLException e) {
        log.error("DB登録に失敗", e);
        throw new SystemException("DBエラー", e);
    }
}
Java

💡ポイント:

  • 入力エラー → 「業務例外」として throw
  • システム障害 → 「システム例外」として throw
  • 正常終了 → return

4. 安全設計チェックリスト

チェック項目内容✅ 推奨
例外はログに残しているか原因追跡可能か
想定内の分岐は return で早期終了ネストを浅く保つ
想定外は例外で止めるfail-fast原則
呼び出し元で例外をキャッチし処理継続するか適切にリカバリしているか
Exception ではなく意味のある例外型IllegalArgumentException, ValidationException

5. 実務応用例(Spring Bootでの安全設計)

@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody User user) {
    try {
        userService.register(user);
        return ResponseEntity.ok("登録完了");
    } catch (ValidationException e) {
        return ResponseEntity.badRequest().body(e.getMessage());
    } catch (SystemException e) {
        log.error("システムエラー", e);
        return ResponseEntity.internalServerError().body("内部エラー");
    }
}
Java


**業務的エラー(想定内)**はHTTP 400、
**システム障害(想定外)**はHTTP 500。
これが「安全設計での return vs throw の分岐」です。


6. まとめ:設計判断早見表

┌───────────────────┐
│ 想定内の条件分岐 → return         │
│ 想定外の異常発生 → throw          │
│ return = 正常な出口               │
│ throw  = 緊急脱出口(警報つき)    │
└───────────────────┘
タイトルとURLをコピーしました