例外をどう書くか

Webアプリのメンテナンスをしていて,例外の扱いがいい加減なのが気になり(元は他人のコード),例外周りを整理しようと思い立った。さてJavaの例外はどう扱うのがスマートか。色々探してみて,役に立つと思ったのが以下の3つ。
例外(Exception)脳の作り方

  • 戻り値にエラーコードをセットするぐらいなら例外を投げよう
  • そうすれば正常系だけがコードの前面に出るヨ

めっちゃ分かりやすいっす。例外のうまい使い方が納得できるなあ。ここでは自分で分かりやすい例外クラスを作って活用する方針。
Best Practices for Exception Handling

  • checked exceptionは使うな(情報の隠蔽が壊れる)
  • 自分で例外クラスはあんまり定義するな(標準の例外クラスを使うかRuntimeException("custom error")を使え)

という方針で,例外をuncheked exceptionにして投げ直す方法を推奨している。
Exception Handling in Web Applications
ここでもchecked exceptionは悪者。NestedExceptionというクラスを作り,例外を補足したらNestedExceptionにラップして(ここ重要。元の例外オブジェクトがそっくり残るのが利点)投げ直している。NestedExceptionは全ての例外をラップするRuntimeExceptionのサブクラス。これをweb.xmlのerror-pageでさらに補足して,意味のあるエラーメッセージを画面に表示するという仕組み。ここで紹介されている3つのアンチパターンがおもしろい。

例外をログした上に投げ直す
  catch (Exception e) {
    e.printStackTrace();
    throw new WrappingException(e);
  }
ログした例外と投げた例外が異なる
  catch (Exception e) {
    // print message only.
    System.err.println(e);
    throw new WrapperException(e.getMessage());
  }
例外を無視する
  catch (Exception e) {
    e.printStackTrace();
  }

checked exception(try/catchするか,クラスがthrowしないといけない例外)は,情報の隠蔽という面からして望ましくない。例えばユーザのIDから属性を取得するクラスがあるとして,このクラスがSQLExceptionを投げていると,クラスを使う側ではこの例外をハンドルしないといけない。ところがSQLを使っているかどうかは,元クラスの実装に依存しており,これをcatchするとクラスを使う側までそれに依存してしまう。
unchecked exceptionはハンドルする必要がない(強制されない)ので,こういう問題が少ない。個人的に方針をたてるとすると,

  • 独自例外は必要に応じて作る
  • できるだけunchecked exceptionを使う
  • 下位レベルからの例外は分かりやすい例外で投げ直す

って感じでしょうか。
しかし独自例外を作るときは例外1つにつき1ファイルですよね。調子に乗ると例外を記述したファイルばかり増えちゃうな。