![]() ![]() ![]() ![]() |
例外を使用したエラー処理 |
ユーザに役立つ関数を提供するために Java クラスのパッケージを設計するとき、クラスが一緒にうまく相互作用し、しかもそのインタフェースが簡単に理解したり使用できることを保証するには、かなり努力がいる。 クラスがあげる例外について考えるのと、それを設計するのとには同じくらい時間を費やさなければならない。
フリーウェアとして配布することを計画しているリンクリストクラスを書いていると仮定する。 他のメソッドにまじって、リンクリストクラスは次のメソッドをサポートする。
- objectAt(int n)
- リスト上のn 番目に位置するオブジェクトを返す。
- firstObject()
- リスト上の最初のオブジェクトを返す。
- indexOf(Object o)
- リスト上で,指定したオブジェクトを検索して、リスト上のオブジェクトの位置を返す。
陥りやすいこと or 発生しやすい問題?
多くのプログラマがリンクリストクラスを使用することになるので、多くのユーザがクラスとそのメソッドを誤用あるいは乱用するのは確実である。 同様に、リンクリストのメソッドを正しく呼び出しても未定義となることもある。 いづれにしても、エラーに直面したら、リンクリストクラスは可能な限り堅牢であって、エラーについて合理的なことを行って、呼出しプログラムにエラーを通信することを望む。 しかし、リンクリストクラスのそれぞれのユーザが、エラーが起こった時オブジェクトがどのように行動してほしいかを予期することはできない。 それで、しばしばエラーが発生する時に行うべき最善策が例外をあげることになる。
リンクリストがサポートしているそれぞれのメソッドは、ある特定の条件の下で例外をあげる ことができ、各メソッドがそれぞれ異なる型の例外をあげることができる。 例を示す。
- objectAt()
- メソッドに渡される整数がゼロ以下の場合、あるいはリスト内に現在あるオブジェクトの数よりも大きい場合に、例外をあげる。
- firstObject()
- リストがオブジェクトを含まない場合に例外をあげる。
- indexOf()
- メソッドに渡されるオブジェクトがリスト内にない場合、例外をあげる。
各メソッドがあげる例外はどんな型でなければならないか? Java 開発環境が用意している例外でなければならないか? あるいは独自の例外を用意するべきか?
あげる例外の型の選択
あげる例外の型を選択する事態に直面した時、2つの選択肢がある。
- 他者が作成した例外を使用する。 たとえば、 Java 開発環境では、使用可能な多くの例外クラスを用意している。
- 独自の例外を作成する。
次の質問に"はい」の答えがあれば、独自の例外クラスを作成するめんどうに立ち向わなければならない。そうでなければ、他の人が作成した例外を使用してめんどうから逃れることができる。
- Java 開発環境にある例外型で表現されない例外型を必要とするのか?
- 他のベンダが作成したクラスがあげた例外とあなたの例外を区別することがユーザの助けとなるのか?
- コードは複数の関連した例外をあげるか?
- 他の人が作成した例外を使用している場合、ユーザがそれらの例外にアクセスすることがあるのか? いいかえると,「パッケージは独立しており,自己完結でなければならないか」。
リンクリストクラスが複数の例外をあげることができ、1つのハンドラを使用してリンクリストがあげるすべての例外をキャッチすることが可能であることは便利である。 同様に、もしリンクリストをパッケージで配布することを計画するなら、すべての関連コードが一緒にパッケージされるべきである。 したがってリンクリストについては、独自の Exception クラス階層を使用するべきである。
次の図は,リンクリストに可能な 例外クラス階層の例です。
LinkedListException は、リンクリストクラスによってあげられるすべての例外の親クラスになる。 リンクリストクラスのユーザは、次のように catch 文を使用して,リンクリスト例外のすべてを処理する1つの例外ハンドラを作成することができる。
catch (LinkedListException) { . . . }あるいは,ユーザは、LinkedListException の各サブクラス用のより特化したハンドラを書くことができる。
スーパークラスの選択
上記の図には LinkedListException クラスのスーパークラスが示されていない。 知ってのとおり、 Java 例外は Throwable オブジェクトでなくてはならない(つまり Throwable のインスタンス、あるいは Throwable のサブクラスのインスタンスでなくてなはならない)。 それで、LinkedListException を Throwable のサブクラスにしたくなる。 しかし java.lang パッケージは、Java プログラム内で発生する問題の型をさらにError と Exceptionに 分ける2つの Throwable サブクラスを用意している。 作成するアプレットとアプリケーションの大部分が、Exceptionであるオブジェクトをあげる。 (Error は、システムの奥ふかくで発生する重大なハードエラー用に予約されている。)
理論的に、Exception サブクラスはすべて LinkedListException の親クラスとして使用できる。 しかし、それらのクラスを一見すると、あまりにも特化されていたり、あるいは完全に LinkedListException と無関係であったりするので、適切ではないことがわかる。 したがって、 LinkedListException の親クラスは Exception とすべきである。
ランタイム例外は、メソッドのthrows 節で指定される必要がないので、多くのパッケージ開発者は「もしすべての例外を RuntimeException から継承させたら簡単になるのではないか?」と質問する。 この質問の答えは ランタイム例外 − 論争 で詳細に説明する。 要点は、クラスが本当にランタイム例外ではない限り、 RuntimeException をサブクラス化するべきではないということである! 大部分の読者にとって、これは「例外は RuntimeException から継承するべきではない。」ことを意味する。
命名規定
Exception クラスから(直接または間接的に)継承するすべてのクラスの名前の最後に「 Exception 」を付けるのは、よい習慣である。 同様に、 Error クラスから継承するクラスは名前の最後に「Error」を付けるべきである。
![]() ![]() ![]() ![]() |
例外を使用したエラー処理 |