Javaの例外処理について頭を整理する

Javaの例外処理機構の背景を考える

Cで例外処理を記述する場合は、下記のような不都合があった。

  • 正常処理の中に例外処理が入り混じる
  • 関数内で例外的な事態となったことを呼び出し元に伝える方法は、戻り値に値域外の値をセットする以外ない

Javaでは、上記の問題を解消するために、下記の機構を採用した。

  • 正常処理は try ブロックに記述する
  • 例外処理は catch ブロックに記述する
  • try ブロックで起こる全ての例外に対して共通して必要な処理は finally ブロックに記述する
  • 呼び出し元に例外的な事態が起こったことを伝えたい場合は、例外オブジェクトを throw する

例外の投げどころを考える

例外を投げると、そのメソッドの処理はそこで中断される。
つまり、「そのメソッドの処理をそれ以上継続できない事態になった時」が投げ時だ。

例外の投げ分けを考える

チェック例外と非チェック例外がある。
大きな違いは、前者を投げるメソッドの呼び出しは try ブロック内でしか行えないということだ。
私は、例外処理が必要か否かは利用者が決めればよいという考えのため、全ての例外は非チェック例外で良いと思っている。
呼び出し元が例外処理をすることを前提にメソッドを作ったなら、その旨をドキュメンテーションコメントに記述すればそれで良い。
(※この点については、後述の「自問自答:なぜチェック例外にした?」でも言及する)

もうひとつの分類軸として、提供元が考えられる。

  • Java標準APIが提供する例外
  • 各種ライブラリが提供する例外
  • 自作例外

上記の並びは、情報の具体性の昇順となっている。
より具体的な例外を投げてやる方が例外発生の原因特定が容易になるので、有用な情報があるなら付加してやると良いだろう。

例外処理を考える

例外処理の目的として、下記が考えられる。

  1. メソッドの処理が中断されたことによって起こる不都合の解消
    1. オブジェクトの不整合の解消
    2. GCされないリソースでかつもう使用されないものの解放
  2. 例外が発生した理由を特定するために役立つ情報の提供
    1. 例外オブジェクトへ情報追加して呼び出し元に throw
    2. エンドユーザに向けてメッセージ出力
    3. システム管理者に向けてログ出力

上記の 1 は必要に応じて常に実施するものであるが、 2 のどれをどのタイミングで実施するかは悩みの種になる。
最近のWEBアプリケーションフレームワークを用いての開発であれば、
開発者は基本的に常に 2-1 を選択し、フレームワークやWebサーバに出力してもらうのが適当だろう。

自問自答:単なる分岐と例外処理の違いは?

具体例で考える。

try {
int num = Integer.parseInt(numStr);
// ①整数であった場合の処理
}
catch(NumberFormatException e) {
// ②整数でなかった場合の処理
}

上記の②の処理内容によっては、この try-catch は例外処理ではなく単なる分岐になる。
(※単なる分岐に try-catch を使うのはアンチパターンである。本来の目的にそぐわない使用方法の弊害はもちろん、例外オブジェクト生成のコストなどもデメリットと言えるだろう。)
②の処理内容がもし、「numStrが文字列であった場合はそれを名前として解釈し〜」といったような処理であれば、これは単なる分岐である。
この場合、例外か否かの判断基準は、「numStrが整数でない場合もこのメソッドを使ってよいか」と言える。
もし使ってよいなら、下記のように単なる分岐にするとよい。

if(isInteger(numStr)) {
// ①整数であった場合の処理
}
else {
// ②整数でなかった場合の処理
}

自問自答:なぜチェック例外にした?

Statement#executeQuery

呼び出し元に、コネクションをクローズしてほしいから?
しかし、下記を見る限り、クローズはそこまで必須でもなさそうではあるが。

close
void close()
throws SQLException

自動的な解除を待たずに、ただちにこの Connection オブジェクトのデータベースと JDBC リソースを解除します。
すでにクローズされた Connection オブジェクトで close メソッドを呼び出すと、操作は行われません。
注: Connection オブジェクトは、ガベージコレクトされるときに自動的にクローズされます。特定の致命的エラーの場合も、Connection オブジェクトはクローズされます。

例外:
SQLException - データベースアクセスエラーが発生した場合

http://192.9.162.55/j2se/1.5.0/ja/docs/ja/api/java/sql/Connection.html#close%28%29

無駄なコネクションを一刻も早く解放したかったり、コネクションプーリングとの絡みとかもあったり・・??

Integer#parseInt

バリデーションエラー、的な・・・??