Since: May./04th/2005
ここでは、例外処理の注意すべき事項についてまとめておきます。
finally
に記述する例外処理で最も重要なのが try-catch
構文の finally
節です。finallyは、例外が発生してもしなくても、JVMが生きている限り、必ず実行されます。リソースの解放のような、必ず実行されなければならない処理は、finally内部に記述します。さもないと、例外発生時にリソースが解放されないなどの状況(リソースリーク)が発生し、システム全体のハングアップ/異常終了に至りかねません。
例えば、全ての例外をException型でキャッチすると、実装できる例外からの回復処理が限られたものに制限されてしまいます。また、実際にスローされた例外的状況を把握することを難しくします。
例外処理も if
や for
と同様に制御構造の一つです。メソッドから抜ける場合に、明示的な戻り値をセットしないで済む裏口として使えますが、コードの可読性が落ちる、スタックトレースの生成処理は一般に重い、スタックトレース自体が巨大などのデメリットがあります。正常な処理の分岐の一つとして例外処理を使うことはパフォーマンス上の誤りです。
開発中は、コーディングエラーを発見するためのプリント文や例外処理を書くことが多いのですが、それらが本番に持ち込まれることは好ましくありません。テストコードは、テストモジュールに含める、ロガーのデバッグモードで制御する、アサーションで実装するなどの方法で、本番リリースするコードからは排除します。本番リリースしたプログラムでの例外処理の本来の役割は、例外的状態からの回復処理を実装することです。
メソッドの throws
リストに挙げられたチェック例外は、メソッドの入出力情報の一部です。プロジェクトの初期の設計段階において、チェック例外と非チェック例外の何れを使うのか決めておくべきです。明確な指針はありませんが、チェック例外であっても、新規に生成した例外オブジェクトにラップすることで任意の例外型に変更できます。
元々の例外情報は、例外チェインを用いて新規生成した例外オブジェクトに含めます。
コア・パッケージでは、色々なメソッドが色々な例外オブジェクトをスローします。例えば、チェック例外である SQLException, IOException, FileNotFoundExeption, SocketException などをそのまま投げると、実装の変更によってスローされる例外が変わってしまいます。実装の変更による修正範囲を該当クラス内に押さえ込むためには、捕捉して処理内容に関する例外でラップして仮想化します。
元々の例外情報は、例外チェインを用いて新規生成した例外オブジェクトに含めます。
throws Exception
を指定することで、もう例外処理に悩むことはなくなります。全ての例外は、チェック例外/非チェック例外の区別無く、コールスタックを伝播します。適当なおまとめクラス(ファサードクラスなど)でログに吐けば終わりです。ただし、これは例外処理の仕組みを放棄することになるので、システム全体で採用するには勇気が要ります。assertion
で実装できます。SEO | [PR] !uO z[y[WJ Cu | ||