例外じゃない例外を作らない、あるいは、例外的状態には例外を使う

  • 6
    いいね
  • 0
    コメント

概要

何やら哲学的なタイトルですが、最近とある SDK で例外っぽい名前の例外でないクラスを見かけたので、頼むからそれは例外にしてくれ🙏という気持ちをここに記しておこうと思います。

例外のような名前の例外でないクラス

ある有名なライブラリにも昔は存在したのですが、非同期処理中におけるエラーを説明するためにFooErrorというクラスを作り(以後この記事では便宜的にエラークラスと言います)、そこにステータスコードやメッセージを詰め込んでコールバックする設計のライブラリや SDK が稀によくあります。

言語によっては例外処理の機構が言語レベルで用意されていないものもあるので、一概にこれがどの場合でも悪手だとは言えませんが、少なくとも例外処理の機構を持っている言語では、例外的状態を説明するのに例外を積極的に使って欲しいです。あるいは、どうしてもやむを得ない理由で例外が使えない場合や、正常系としての振る舞いとして失敗したという結果を返したい場合は、ErrorException等の例外を想起させるクラス名は使わないほうが良いです。

このあたり、某有名ライブラリにあがっているイシューでは、「あの設計はひどかったからやめたよ」とコメントされていたりしています。

エラークラスで困ること

スタックトレースが取れない

例外の機構を使わない場合、スタックトレースがそのままでは得られないので、どこでなにが起きてだめだったのかという情報が欠落します。エラークラスに状況を説明するためのステータスコードやメッセージを含めるパターンが多いと思いますが、似たようなエラークラスの生成が複数箇所で行われると追いきれません。自分で例外クラスを拡張してステータスコードやメッセージを含められるようにすれば、晴れてスタックトレースも見えるようになるはずです。

投げられそうに見えて投げられない

Java言語であれば、例外クラスはたいていFooExceptionBarErrorなど語尾にExceptionErrorがついています。おそらく他の言語でも例外を表すクラス名には一定の命名規則やパターンがあると思います。

これと似たような名前のエラークラスを見かけると、一見投げられるのかな?と思ったり、Throwableを吸い込んでくれる便利ユーティリティ(例えば、例外をログに出すようなメソッド)にそのまま渡せるかな?と思ったりしますが、その実まったくThrowableではないので、通常の例外処理の機構にのっとった取り扱い方ができません。

さいごに

EffectiveJava 第二版では、例外的状況にのみ例外を使うと題して、通常の制御構造として例外を使ってはいけないという事例が載っています。合わせて振り返っておきたい項目です。