山崎屋の技術メモ

IT業界で働く中でテクノロジーを愛するSIerのシステムエンジニア👨‍💻 | AndroidとWebアプリの二刀流🧙‍♂️ | コードの裏にあるストーリーを綴るブログ執筆者✍️ | 日々進化するデジタル世界で学び続ける探究者🚀 | #TechLover #CodeArtisan、気になること、メモしておきたいことを書いていきます。

java の例外設計

プロジェクトの設計フェーズ序盤で、例外の扱いについて方針を決める必要がある。

もし、自分が方針を決めるとしたらこうするというものをメモしておく。

1.検査例外と非検査例外の使い分け

最近では検査例外を悪と考え、すべて非検査例外にラップしてスローしなおすという場合もあるようだ。

これを機能として提供しているフレームワークもある。

しかし、検査例外と非検査例外は理由があって分かれているので、私はちゃんと使い分けるべきと考えている。

検査例外

プログラムが正しくても起こりうる例外。

例えば、

  • 読み込もうとしたファイルが他のプログラムにより消された
  • デッドロックした
  • ユーザがブラウザの戻るボタンを使って、想定外の操作をした

などである。こういう場合には検査例外を使用する。

「オイラの処理には防ぎきれないエラーが発生する可能性があるので、注意しておいてね」というのがtry ~ catch の強制(または throws 区の強制)である。

なので特別な理由がなければ非検査例外にラップしてスローなどは行わない。

非検査例外

プログラム内で発生を防げるにもかかわらず発生した例外。

Null チェックを怠ったために発生した NullPointerException 。配列のインデックスをチェックしていなかったために発生した
ArrayIndexOutOfBoundsException 等。

これらの例外が発生したのであれば、プログラムのバグとして、プログラムを修正する。

2.例外のスローの仕方

できるだけ、細かくスローする。

FileNotFoundException と IOException の両方が発生する可能性がある場合、メソッド宣言の throws 区には IOException だけを書くこともできる。(IOException は FileNotFoundException の親クラス。)

だけど、特別な理由がない限りは両方書くべき。

例外を受け取ったクラスが、その例外をどのように扱うかは呼び出し先のクラスは関知できない。

だから、例外のハンドリングに必要と思われる情報は、なるべく細かく伝えてあげる必要がある。

3.例外のキャッチの仕方

細かくキャッチするか、親クラスでまとめてキャッチするか、極論を言えば「catch (Exception e)」としてしまうか、全体の方針として明確にしない。

責任を持ってハンドリングするという目的が達成できるのであれば、どのようにキャッチするかは各処理の設計にゆだねる。

4.独自例外

なるべく作らない。Java 標準の例外で目的に沿うものがあればそれを使う。

業務独自の例外を作らなければ対応できない場合のみ作る。

無条件に独自例外にラップしてスローしているシステムも見かけたことがあるが、まるで意味がなかった。そのプロジェクトで出力される例外のスタックトレースには、まず独自例外の出力があり、その後、Java 標準の例外出力がある。そして結局 Java 標準の例外メッセージを見て解決策を考えることになる。

まとめ

今のところこんな感じで整理している。追加や変更は随時行っていく。

もちろんプロジェクトの特性により、当記事の方針では実装できない(しにくい)場合も必ずあるので、絶対に守らないとダメっていうものでもない。

でわ。

Effective Java 第2版 (The Java Series)

Effective Java 第2版 (The Java Series)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)