okinawa

IT勉強メモ

例外設計の基本メモ

職場で例外処理を書くことになった。

他の人のコードを参考にしようとしたけど、どれも書き方がまちまちで正解がわからなかったので、ちょっと勉強したことのメモ。

ちなみに例外とエラーの違いは下記のようになるみたいだけど、ここでは同じものとして扱います。

  • 例外:「想定できた」おかしな状態
  • エラー:「想定外の」おかしな状態

例外の分類

ユーザーが引き起こすエラー(業務エラー)

ユーザーによる入力ミスや不正な操作によるエラー。

ミスではなくてもユーザーの入力値によるエラーも含まれる。

例えば、会員登録ですでに使われているメールアドレスで登録しようとした場合の重複エラーなど。(排他エラー)

操作を改善すれば回復可能。

プログラマが引き起こすエラー(システムエラー)

コーディングミスや考慮不足によるエラー。

いわゆるバグ。

コードを修正すれば回復可能。

環境が引き起こすエラー(システムエラー)

アプリケーション外部の要因が引き起こすエラー。

DBの接続切れ、回線不良、容量不足など。

たとえば、アプリケーションから動画をダウンロードしようとしたが、保存先の容量不足で保存できなかったとか。

自然災害なども含まれる。

回復不可能な場合あり。

例外への対処法

ユーザーが引き起こすエラーへの対処法

ユーザーに操作の改善を促すメッセージを表示する。

「名前の入力は必須です」みたいなの。

開発者なら何度も書いていると思う。

プログラマが引き起こすエラーへの対処法

ユーザーに運用担当への連絡を促す共通エラーメッセージを表示する。

「エラーが発生しました。IT運用部門へご連絡ください。」など。

また、ログ出力も必須。

catchせずに貫通させてフレームワークに任せて良い。

環境が引き起こすエラーへの対処法

可能性が多すぎて対処方法は無いように思われる。

とりあえずどうしようもない時はアプリケーションを終了する。

考慮すべき例外は?

上に書いた例外への対処法とかぶるけど一応書いておきます。

ユーザーが引き起こすエラー

基本的にはこのユーザーエラーについて考慮する。

どのような操作をしたときにどのようなメッセージを表示するか。

DBのUPDATE時の排他エラーも含まれます。

プログラマが引き起こすエラー

プログラマが引き起こすエラーについてはログ表示と共通のエラーメッセージを表示させる。あとはフレームワークに任せてOK。

環境が引き起こすエラー

考慮しない。

災害時対応や停電対応などは別の方々のお仕事になる。

try catchとthrows Exceptinの併用は何のため?

けっこうよく見かけるこういうの↓

 public void test() throws Exception {
        try {
            int a = 1 * 2;
        } catch(Exception e) {
            e.printStackTrace();
            throw new SQLException(); //例外をcatchした上でまた例外を投げる
        }
    }

なぜcatchした上でまた例外を投げるのか謎だった。

どうやらわかりやすい例外クラスで投げるのが目的らしい。

例えば自作の例外クラスなど。

teratail.com

検査例外と非検査例外の違い

非検査例外

try catch不要。
NullPointerやArrayIndexOut~などのException。
非検査例外は発生すると、勝手にスタックトレースを表示してくれる。

検査例外

try catchが必要。
catch文の中でスタックトレースやエラーメッセージを表示するよう書かないと何も表示されない。
なのでcatchだけして、何もせず例外を握りつぶすこともできてしまう。
IOException SQLExceptionなど。

ちなみに検査例外と非検査例外がどういう基準で分けられているかは議論の余地があるようで調べてもはっきりとはわからなかった。
とりあえず検査例外は呼び出し元(ユーザー側)で回避や回復可能な例外なのかしら。

参考

エラーチェックの体系的な分類方法 | Microsoft Learn

プログラム設計でのエラー処理. (エラー処理は問題対処の放棄ではない) | by 読み人知らず | Medium

例外設計における大罪

Javaの検査例外は、呼び出し側で「どんなに注意しても防げない」異常系 - Qiita