[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends-ml 1470] Re: assertion 、事前 条件の例外スロー方法



前橋です。

著者校正終了... 現在は再校中。作業的には一区切り付きました。

高橋(徹)さん:
>「契約による設計」をキーワードにあちこちを探ってみました。
>
>> > >    ◇P9
>> > >        ソースコードの引数チェックにおいて、例外をthrowしているが、こ
>> > >      のような処理は良いものなのか、疑問があるという意見あり。
>> > >        (スレッドとは関係無い話ですが)
>> > 
>> > これはEiffelとかにある「事前条件」をJavaでやってみた、ということなのでは?
>> 「有無を言わせずRuntimeExceptionで落してしまうのはよくないのでは?」
>> という意見です。開発時はよいのですが、運用時にRuntimeExceptionで落ちる
>> のはまずいよねという内容だったと思います。
>JavaReport誌1998年9月号の記事"Prevention Is Better Than A Cure"および、
>JavaReport誌1999年5月号の記事"Concurrent Contracts"(双方Mike Mannion著)
>において、Design by Contractについて解説されていました。
>前者では、Assertionの実装例と使用例が載っています。RuntimeExceptionを
>スローするかException(非RuntimeException)をスローするかについては議論が
>あるようです。

今はもう辿れませんが、昔 Sun の Web サイトにあったJava programmer's
FAQ には、Assert の実装例が載っていて、それでは RuntimeException を
投げていました。

>なお、事前条件はassertによってチェックすべきではないと述べられており、
>通常のコーディングによって引数をチェックし、例外として
>IllegalArgumentException等をスローすることを勧めています。

この手の指針は、私はちょっとどうかと思います。

例えば、年齢を引数として受け取るメソッドで、マイナスの値がやってきたら
そりゃ上位のルーチンが決定的に「バグっている」わけで、そんな状態から
処理を続けてもろくな結果が出るわきゃなかろう、と思うからです。

だから、assertでは、RuntimeExceptionを投げるどころか、スタックトレースを
吐いてSystem.exit()しちゃってもいいぐらいだと思います。JavaOSで動いてる
とかでなければ。

もちろん、呼び出され側である程度の処理をしないと引数の妥当性が
わからない、だから、呼び出し側では、とりあえず呼んでみて
IllegalArgumentExceptionをcatchする、というケースは話が別ですが。

...というのが、C 言語野郎としての私の意見なわけですが、

C だと、ムチャな引数が渡ってくる(バグっている)ということは、
どこかで深刻な領域破壊が起きている可能性が高いわけで、そういう
時には、もうそのプログラムの挙動はまるであてにならないのだとしても、

Javaの場合、基本的に領域破壊はないので、「あっちの方はバグってる
けど、こっちはまだ元気」ということを期待してもよいのかもしれません。
グローバル変数を書きかえられたりしてたら結局一緒でしょうが、その辺は
「うまくやれば」可視性の制御などにより分離できるかもしれません。

また、C の場合、例えば戻り値でエラーステータスを返しても、
呼び出し側でチェックをさぼっている可能性がかなり高く、致命的な
バグの時に悠長にステータスなんぞ返すよりもとっとと殺してしまった
方が確実にバグを捕捉できる、という事情もあるわけですが、Javaなら、
例外はたとえチェックをさぼっても最終的に捕捉できるので、安全かも
しれません。

でも、

  try {
      処理;
  } catch (Exception ex) {
      ;
  }

こんなことされてちゃ困るなあ... そのぐらいならいっそ、Errorを
投げる方がより確実かも。

それに、Javaだと、動的なクラスロードがあるわけで、

例えば、Javaで書いたブラウザがあったとして、変なアプレットひとつ
読みこんだぐらいでブラウザ全体がコケてしまっては困ります。
例えば、変なアプレットが、Graphicsクラスの何かのメソッドを呼んで、
その引数がムチャクチャだった場合などですね。

じゃあ、「Graphicsクラスの何かのメソッド」で「ちゃんと」引数
チェックを行なって、例外を投げて... も、処理が戻るのはその怪しげな
アプレットまでなわけで、やっぱりいまいちです。どうせなら、
そのアプレットのpaint()メソッドの呼び出し元まで戻って、
そんな腐れたアプレットはとっととアンロードしちまって、「なかったこと」
にしたいですよね。

そういうのを実現するにはどうすればいいのかなあ、というのを、
以前から考えているのですが、なんとも...

例えば、その腐れアプレットが、「フレームワーク側」のメソッドを
ごちゃごちゃに呼んで、それが妙な副作用を残していたりとかしたら...

うーん、うーん。

------------------------------------------------------------
  前橋 和弥              maebashi@xxxxxxxxx
                         http://member.nifty.ne.jp/maebashi/
------------------------------------------------------------