- PR -

NumberFormatException が非チェック例外なのはなぜ?

投稿者投稿内容
やまろう
常連さん
会議室デビュー日: 2003/10/13
投稿数: 35
お住まい・勤務地: 埼玉・東京
投稿日時: 2003-11-20 13:18
例外について、「実践 J2EEシステムデザイン」って言う分厚い本の中で、

「チェックされる例外は例外の数が少ないうちは、とてもうまくいき素晴らしいもの
だと感じられるが、例外の数が多くなるとむしろ邪魔になってくる。」

ってなことを言っています。

例外をcatchするコードがあまりに多いとコードの可読性は低下しネストした例外処理は
ミスを犯す可能性が高い(途中で例外が途絶えたり)。さらにチェックされる例外を
catchして新しい例外でラップしてまた投げる、またはメソッドの宣言にthrowsを
書いてただ呼び出し元へと投げられるような無意味なことが多い。

ということでこの本の著者は
むしろRuntimeExceptionを標準にした方が良いのではないかと提案しています。
で、どうしても呼び出し側に知らせたい場合のみ、チェックされる例外にすれば良いと。

僕もこの著者の意見に賛成です。
大抵例外を処理できるのなんて一番頭の呼び出し元ですもの。

そう考えるとWebアプリケーションで、チェックされる例外を
自分で定義するような場面ってないんじゃないかと思います。どうせ呼び出し元に
向かってスルーしてくだけなんだから。たとえばユーザの入力ミスを表す
InvalidInputExceptionってのを定義するとしても入力チェックでこの例外を投げたら
処理できるのなんてエラー画面だす処理をするクラスだけであって、このクラスまで
ずっと例外をスルーしてくだけじゃないかと。もしもInvalidInputExceptionを
チェックされる例外にしたら入力チェックを行うクラスからエラー処理するクラスまで
全てにthrowsを書かなければならず、無意味だと思います。

なので、現実的に考えてNumberFormatExceptionを入力値エラーの判定に使ったって
良いと思います。概念的にRuntimeExceptionをcatchするのは良くないからとかじゃなく
必要だったらcatchすりゃいいし、その方がシンプルに出来るならそれでいいんじゃ
ないかと思います。

ということで、チェックされる例外は大抵おせっかいなのであまり好きではないの
ですが、この機能もコンパイラで出来る限りプログラミングのミスを減らそうって
いう試みなんでしょうね。
例えばif文の==って書くのを=って書いたらコンパイルエラーになると同じように。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-11-20 14:58
unibon です。こんにちわ。

引用:

やまろうさんの書き込み (2003-11-20 13:18) より:
例外について、「実践 J2EEシステムデザイン」って言う分厚い本の中で、

「チェックされる例外は例外の数が少ないうちは、とてもうまくいき素晴らしいもの
だと感じられるが、例外の数が多くなるとむしろ邪魔になってくる。」

ってなことを言っています。


私も同感です。
これを避けるためにも、例外の必要性がないものは、
例外以外の戻り値などで返すべきだと思います。

引用:

やまろうさんの書き込み (2003-11-20 13:18) より:
例外をcatchするコードがあまりに多いとコードの可読性は低下しネストした例外処理は
ミスを犯す可能性が高い(途中で例外が途絶えたり)。さらにチェックされる例外を
catchして新しい例外でラップしてまた投げる、またはメソッドの宣言にthrowsを
書いてただ呼び出し元へと投げられるような無意味なことが多い。


これもこの著者に同感です。

引用:

やまろうさんの書き込み (2003-11-20 13:18) より:
ということでこの本の著者は
むしろRuntimeExceptionを標準にした方が良いのではないかと提案しています。
で、どうしても呼び出し側に知らせたい場合のみ、チェックされる例外にすれば良いと。


これには納得いかない感じがします。
この本は読んだことがないのでニュアンスは分からないのですが、
起きる可能性のあるエラーが非チェック例外でいきなり throw されても、
受けるほうは困ってしまいます。
javadoc の @throws に頼らなくても、メソッドが throw する可能性がある非チェック例外を
すべて網羅できるような環境があればよいのですが。

なお、その後考えていたら、
NumberFormatException が非チェック例外な理由がなんとなく分かりました。
NumberFormatException はコンストラクタの引数チェックなどで使われることが多く、
コンストラクタ内で起きたエラーを返すのに戻り値の仕組みを使おうとすると、
別途 getter 等のアクセッサを呼ばなければならず不便であり、実用的ではありません。
したがって例外で返さざるを得ないのですが、この著者の意見のように、
チェック例外だといちいち catch しなくてはならず面倒になります。
それで非チェック例外に落ち着いているのだと思います。
Anthyhime
ぬし
会議室デビュー日: 2002/09/10
投稿数: 437
投稿日時: 2003-11-21 07:57
例外の生成はものすごくコストがかかるので、毎回発生するような数値型のチェックにparseInt()はよろしくないですね。(それにparseInt()は全角数値とかキリル文字とかロシア文字とか通してしまいますし。)
SunはparseInt(String)でNumberFormatException投げるぐらいだったらNumber系クラスに
boolean isVaild(String)
みたいなメソッド用意しろって感じですな。
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-11-21 12:10
引用:

Anthyhimeさんの書き込み (2003-11-21 07:57) より:
例外の生成はものすごくコストがかかるので、毎回発生するような数値型のチェックにparseInt()はよろしくないですね。(それにparseInt()は全角数値とかキリル文字とかロシア文字とか通してしまいますし。)
SunはparseInt(String)でNumberFormatException投げるぐらいだったらNumber系クラスに
boolean isVaild(String)
みたいなメソッド用意しろって感じですな。


そうですね。ところで、キリル文字の数字って使えます?漢数字とギリシャ数字を受け付けないのに。(キリル文字の数字がどれだかわからないので...)

パフォーマンスを重視するなら、isVaild(String)の場合、チェックが二重になってしまうので
戻り値をラッパ型/nullにしてくれたほうがいいかな。

あと、チェック例外と非チェック例外の使い分けに関してはEffective Javaには
次のようにかかれていました。
引用:

例外状態がAPIの適切な使用では防ぐことができなく、かつ、そのAPIを使用しているプログラマが例外に直面した時になんらかの有用な処理をすることができる場合に、その負荷は正当化されます。この両方の条件が満たされない限り、チェックされない例外の方が適切です。


#補足
引用文中の「その負荷」とは、プログラマが例外をハンドリング(throws宣言、try-catch)することを強制されることです。

[ メッセージ編集済み 編集者: Wata 編集日時 2003-11-21 12:50 ]
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-11-21 12:43
引用:

パフォーマンスを重視するなら、isVaild(String)の場合、チェックが二重になってしまうので戻り値をラッパ型/nullにしてくれたほうがいいかな。


または、代替案として、isValied()は指定したロケール(またはデフォルトロケール)でfail-fastでチェック(無効な文字が出た所で抜ける)し、parseInt()は指定したロケール(またはデフォルトロケールで)無理やり変換してしまうというのもありかな。
やまろう
常連さん
会議室デビュー日: 2003/10/13
投稿数: 35
お住まい・勤務地: 埼玉・東京
投稿日時: 2003-11-21 15:16
意見センキュー、unibonさん

  引用:
  ----------------------------------------------------------------------------    
    unibonの書き込み (2003-11-20 14:58) より:
    引用:
    ------------------------------------------------------------------------    
    やまろうさんの書き込み (2003-11-20 13:18) より:
    ということでこの本の著者は
    むしろRuntimeExceptionを標準にした方が良いのではないかと提案しています。
    で、どうしても呼び出し側に知らせたい場合のみ、チェックされる例外にすれば
    良いと。

    ------------------------------------------------------------------------    
    これには納得いかない感じがします。
    この本は読んだことがないのでニュアンスは分からないのですが、
    起きる可能性のあるエラーが非チェック例外でいきなり throw されても、
    受けるほうは困ってしまいます。
    javadoc の @throws に頼らなくても、メソッドが throw する可能性がある
    非チェック例外をすべて網羅できるような環境があればよいのですが。
  ----------------------------------------------------------------------------

とのことですが、「javadoc の @throws」以下のことには賛成なんですけど、
「納得いかない」ってとこで、

えーと、「実践 J2EEシステムデザイン」は先輩から借りて読んだので今手元にない
のですが(なんせ6500円もするんで)
この本の著者が言いたいのは、チェックされる例外を投げられても、呼び出し側が何も対処出来るようなことがないような例外なのにチェックされる例外を投げてる場面が多いんじゃないか?それなのにtry-catchまたはthrowsを書くことをコンパイラによって強制されて
やんなっちゃうよっていうようなニュアンスなんだと思います。呼び出し側で対処出来なくてthrowsを最初の呼び出し元まで書いてくだけのような例外だったらRuntimeExceptionにしてもいっしょですよね!

ということで、むやみにチェック例外を使いすぎてるからRuntimeExceptionを標準にして
チェック例外を作る時は呼び出し側が対処できるかってことを開発者に意識させようぜという感じなんじゃないですかね。





[ メッセージ編集済み 編集者: やまろう 編集日時 2003-11-21 15:21 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-11-21 15:57
unibon です。こんにちわ。

引用:

やまろうさんの書き込み (2003-11-21 15:16) より:
えーと、「実践 J2EEシステムデザイン」は先輩から借りて読んだので今手元にない
のですが(なんせ6500円もするんで)
この本の著者が言いたいのは、チェックされる例外を投げられても、呼び出し側が何も対処出来るようなことがないような例外なのにチェックされる例外を投げてる場面が多いんじゃないか?それなのにtry-catchまたはthrowsを書くことをコンパイラによって強制されて
やんなっちゃうよっていうようなニュアンスなんだと思います。呼び出し側で対処出来なくてthrowsを最初の呼び出し元まで書いてくだけのような例外だったらRuntimeExceptionにしてもいっしょですよね!


すみません。著者の意図を誤解していました。それなら納得できます。
「呼び出し側が何も対処出来ない」場面ならば、非チェック例外である、
IllegalStateException や IllegalArgumentException や NullPointerException 等を、
バシバシ投げるのは好ましいことだと思います。

ただ、「呼び出し側が何も対処出来ない」かどうかの判断が難しいと思います。
たとえば assert があって assertion を満たさない場面なら、
「呼び出し側が何も対処出来ない」と思いますので、
非チェック例外は投げても良いでしょう。
しかし、たとえば NumberFormatException が投げられるような場面では
「呼び出し側」は、「入力が正しくありません」とダイアログを出したり、
そのような Web のレスポンスを返して対処することは可能です。
やはり parseInt/parseDouble や new Integer(String)/new Double(String) をする前には、
それらのメソッドとは別のやりかたで、引数のチェックは済ませておくべきなのでしょうか。
#と、なんだか最初の質問に戻ってしまいました。
架空兎
ベテラン
会議室デビュー日: 2003/08/18
投稿数: 78
お住まい・勤務地: さいたま氏
投稿日時: 2003-11-21 17:17
私の推測なのですが、NumberFormatException は IllegalArgumentException の
サブクラスであることから、Integer#parseInt メソッド等の引数には解析可能な文字列を
渡すことを前提としているのではないでしょうか?
#例えば、数字しか入力されない項目から取得した文字列であれば例外をキャッチする
#必要はないですよね?

もし、解析可能かどうか分からない文字列を解析する場合は java.text.NumberFormat クラスの
parse メソッドを使う、ということなのではないでしょうか?
# parse メソッドが発生させる java.text.ParseException はチェック例外。

スキルアップ/キャリアアップ(JOB@IT)