【初心者必見】なぜ例外をキャッチせずにスローだけするの?理由をわかりやすく解説!

こんにちは。ゆうせいです。

「例外って、発生したらキャッチすべきじゃないの?」
そう思ったことはありませんか?

今回は、Java標準ライブラリのparseIntメソッドを題材に、
例外をキャッチせずにスローだけする理由を、しっかり理解してもらいます!


まずparseIntの実装を確認しよう

JavaのIntegerクラスにあるparseIntメソッドはこんな感じで定義されています。

public static int parseInt(String s, int radix)
        throws NumberFormatException
{
    if (s == null) {
        throw new NumberFormatException("Cannot parse null string");
    }
    // (この後、文字列を整数に変換する処理が続く)
}

ポイントは、
throws NumberFormatException
がメソッドシグネチャに明示されていることですね。


ここでのスローの意味とは?

ここでスローしている理由は、非常にシンプルです。

「このメソッド単体では、エラーにどう対処すべきかを決められないから」

ということです!

parseIntの責務(やるべき仕事)は、

  • 正しい文字列を整数に変換すること

だけです。

エラー(例えばnullの文字列)が起きた時、どう対応するか?
それは、このメソッドを呼び出した側が決めるべきことであり、parseIntが勝手に判断してはいけないのです。


もしここでキャッチしてしまったら?

仮にparseIntの内部で例外をキャッチして無理やり続行したらどうなるでしょうか?

例えば…

if (s == null) {
    try {
        // 無理に0を返すなど
        return 0;
    } catch (Exception e) {
        // ログだけ出して無視
    }
}

こんな実装をしてしまうと、

  • 本来エラーで気づけるはずのバグが隠れてしまう
  • 無意味な値(ここでは0)がプログラムに流れて、後で深刻な不具合になる

という大問題が起こります!

つまり、小手先でごまかすと、もっと大きなトラブルの元になるのです。


正しい責任分担とは?

まとめると、

レイヤー役割
parseIntメソッド正常なら変換する、異常なら例外をスローする
呼び出し元例外をキャッチして適切に対応する(リトライ、エラーメッセージ表示、終了など)

という役割分担になります。

これを崩すと、

  • ライブラリコードが過剰に重たくなる
  • ユーザー側の柔軟性が失われる

といった悪影響が出ます。


図で理解するスローの流れ

簡単な流れを図解します!

【ユーザーコード】  → parseInt("abc")
                               ↓
    "文字列を整数にできない!"
                               ↓
【parseIntメソッド】  → 例外をスロー(throw)
                               ↓
【ユーザーコード】  → catchして適切に対応

まとめ:なぜキャッチせずにスローするか?

  • 自分(メソッド)の責任範囲を超える問題には、自分で対処しない
  • 例外は、呼び出し元に伝えて「どうするか」を任せる
  • スローすることで、プログラム全体の安全性と柔軟性を保つ

つまり、

「何でも自分で解決しようとしない!ちゃんと伝える!」

これがプロフェッショナルな例外設計なんです!


今後の学習の指針

ここまで理解できたら、次は

  • throwsとthrowの違い
  • チェック例外と非チェック例外の違い
  • エラー伝播パターン(例外チェーン)
  • 例外をきれいに扱う設計パターン(例えば「Try-Catch Wrapper」)

にもチャレンジしてみましょう!

例外処理の腕前がグンとアップしますよ!


セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。