2017年12月8日金曜日

Exception の使い処

Perl では Exception のことは気にしないでプログラミングできたので、Java で当初特異に感じたのが Exception の扱いだ。仕様に強制される形で try-catch を行う必要があるという認識で今まで凌いできた。

そもそも CUI でプログラミングしている段階では、例外処理については別段の配慮はせずとも、コンソールに JVM が吐くエラーメッセージが表示されるので、自分でエラーに備える処理を明示的にコーディングする必要はなかった。CUI というのはそういった意味でユーザーとプログラマーが完全に同一レベルの視点で体験を共有しているので、ある意味貴重な環境なのかもしれない。

そういった CUI の貴重な環境の習慣をそのまま引き摺ってしまっていて、GUI で Android のアプリなどを作っていても、例外処理について、標準メソッド側が要求するから受動的に try-catch を記述する程度で、自分から能動的に Exception クラスを用いるという経験があまりなかった。

ところで最近 Web のフォーム送信操作を自動化する Java プログラムを作成していて、想定外のエラーが発生した時、そのエラーがどの段階で出たエラーなのかということがわかった方が、自分自身で利用するだけでなくもしアプリを公開するという前提では、その方が良いと考えた。そこで、各段階で、想定通りではない結果になっていた場合、Exception を発生させるようなコードにすることにした。

当初は字義的に、RuntimeException を使っていた。ところがこれでも「どの段階で発生したのか?」がわかりにくかったので、最終的には IOException を使うことに落ち着いた。

GUI ライブラリーとして Lanterna という ncurses ライクなライブラリーを使っており、コンソールではなく、GUI の表示にエラーメッセージも表示させたいと考えた。当初の RuntimeException だと、どこかでエラーが発生していることがコンソールには表示されるのだが、どの段階で起ったのかが把握しにくく、GUI 側でもどこでキャッチすればいいのかがわかりにくい。そこで IOException にして、GUI 側で catch させることにしたのである。

ネットワークにアクセスしているので、標準ライブラリーからも IOException が発生する可能性があり、try-catch または throws 対応をしなくてはならない。これまで、throws の使い処がよくわからず、throws してもどの道さらにその上流の呼出元で catch しなければならなくなるだけで、いくらでも連鎖するので、とっとと catch した方がいい、と単純に考えていた。

ところが、今回のように例外はできるだけ GUI の層(MVC のうちの VC に相当)で処理することにすると、中核のフォームの送信などのネットワーク処理を行う層(MVC の M に相当)では例外はひたすら throws して呼出元に回した方がいいとわかった。標準ライブラリーから発生するものも throws し、また想定外の状態に陥った場合は throw new IOException() して throw する。catch するのは、Lanterna を使った GUI コードの層のクラスにおいて行う。そこで catch したエラーを GUI を通じてメッセージとして表示すればいい。

このようにしておくと、他のユーザーが使ってエラーが発生した時、エラーメッセージを表示してその情報を元にサポートする手掛かりを易くできる。

0 件のコメント:

コメントを投稿