- PR -

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

投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-11-17 11:19
unibon です。こんにちわ。

java.lang.NumberFormatException は java.lang.RuntimeException のサブクラスであり、
すなわち、非チェック例外です(catch しなくてもコンパイルエラーにならない)。
これはなぜなのでしょうか。

私が持っている、例外に対する認識としては、非チェック例外を catch するのは、
よほどのことがない限りすべきではないと思っています。
#以下、これを仮定して断定的に書きますが。
たとえば、コンソールにスタックトレースが出るのを抑止したいとか、
そういうシステム寄りのソリューションでなら非チェック例外を catch するのもやむを得ないと思いますが、
アプリケーションのコードの中でたかが文字列から数値への変換で
非チェック例外を catch するのはやりすぎです。
NumberFormatException はチェック例外であるべきか、
あるいは、フォーマット検査の結果を例外ではなく戻り値で返すべきです。
単に、過去にうっかり非チェック例外にしてしまったので、
互換性を保つためにそれが続いているだけ、という認識でよいでしょうか。

ちなみに、疑問の中心としては、
別に NumberFormatException をことさら問題にしているわけではないのですが、
上記の私の認識に対して NumberFormatException だけがこれに沿っておらず、
"例外" になっているので、私の認識が正しくないのか、という疑問があります。
ぽん
大ベテラン
会議室デビュー日: 2003/05/13
投稿数: 157
投稿日時: 2003-11-17 12:05
引用:

以下全て、unibonさんの書き込み (2003-11-17 11:19) より:



引用:

java.lang.NumberFormatException は java.lang.RuntimeException のサブクラスであり、
すなわち、非チェック例外です(catch しなくてもコンパイルエラーにならない)。
これはなぜなのでしょうか。


NumberFormatExceptionは実行時の値によって発生する/しないが決まる例外(つまりRuntimeException)だからです。

引用:

あるいは、フォーマット検査の結果を例外ではなく戻り値で返すべきです。


クラスの仕様上「例外」となっているものを引数で返すのは問題だと思います。
この辺は、NumberFormatExceptionの問題ではなく、クラスの仕様の問題では?

[追記]
NumberFormatExceptionを「例外」としない仕様のクラスを作成するのなら
引数で返しても良いと思います。

[ メッセージ編集済み 編集者: ぽん 編集日時 2003-11-17 12:15 ]
Keisuke
大ベテラン
会議室デビュー日: 2003/10/24
投稿数: 105
投稿日時: 2003-11-17 12:48
非チェック例外とは、「発生しないことを保証できるコーディングが
可能な例外」と考えてはいかがでしょうか?
でくのぼう
大ベテラン
会議室デビュー日: 2003/10/06
投稿数: 162
投稿日時: 2003-11-17 12:48
引用:

NumberFormatException はチェック例外であるべきか、
あるいは、フォーマット検査の結果を例外ではなく戻り値で返すべきです。



フォーマット検査を行わない値をいきなり数値変換するから「例外」が起こり得るわけで
その前に然るべき検査を行うのが言語仕様に沿ったコーディング方法と言えるのでは?

検査していない値を、数値に変換可能な文字列などを期待するメソッドに渡すという行為が
そもそも理にかなっていないというか。
(だから「わざわざcatchするのはやりすぎ」なんですよね。)

NumberFormatExdeption を検査代わりに使うのは一種のSyntax Sugarと言えるかも。
DaikiRyuto
大ベテラン
会議室デビュー日: 2002/07/23
投稿数: 200
投稿日時: 2003-11-17 13:48
NumberFormatExceptionがcatchできないのを知らない、というのは割とよくあることだったりしますね。Java経験3年とかでもそうだったりする場合も。
なんでこうなってるのかは色々と言われてますけど、あんまり納得できたことはありませんね。

引用:

フォーマット検査を行わない値をいきなり数値変換するから「例外」が起こり得るわけで
その前に然るべき検査を行うのが言語仕様に沿ったコーディング方法と言えるのでは?


ちょっとした疑問ですが、これをやるとチェックが2回になってしまいませんか?
でくのぼう
大ベテラン
会議室デビュー日: 2003/10/06
投稿数: 162
投稿日時: 2003-11-17 15:28
引用:

NumberFormatExceptionがcatchできないのを知らない、というのは割とよくあることだったりしますね。Java経験3年とかでもそうだったりする場合も。
なんでこうなってるのかは色々と言われてますけど、あんまり納得できたことはありませんね。



catch できない?
どういう事でしょう?

コード:
String str = "abc";
int i;

try {
    i = Integer.parseInt(str);
} catch (NumberFormatException e) {
    System.out.println("Exception occurred.");
}



上のような実装ではcatchできますが???
こういう話ではないですか?


引用:

引用:

フォーマット検査を行わない値をいきなり数値変換するから「例外」が起こり得るわけで
その前に然るべき検査を行うのが言語仕様に沿ったコーディング方法と言えるのでは?


ちょっとした疑問ですが、これをやるとチェックが2回になってしまいませんか?



たしかにチェックは重複します。
// java.lang.Integer では Charactor.digit() を使ってチェックしています。

しかし、オブジェクト指向的にはチェックが多重化する事を
それほど重大な事と認識するかは疑問です。

あくまでオブジェクトとオブジェクトはそれぞれに用意されたインタフェースを
用いて相互に通信(会話)を行うものですから、相手のオブジェクトの内部が
どんな実装になっているのかを知る必要は無いですから。

そのため呼び出し元のオブジェクトは呼び出し先が用意している
インタフェースに沿った値を渡してやるのが自然と思われます。

呼び出し先のオブジェクトが吐き出す例外をアテにするのが
好ましい実装であるかは、まあ人それぞれの考えによりますけどね。
仮にそれが非効率的であっても、私は好ましくないと考えます。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-11-17 16:32
unibon です。こんにちわ。

引用:

Keisukeさんの書き込み (2003-11-17 12:48) より:
非チェック例外とは、「発生しないことを保証できるコーディングが
可能な例外」と考えてはいかがでしょうか?


非チェック例外とは、
http://www.y-adagio.com/public/standards/tr_javalang2/exceptions.doc.html#44121
にある
「非検査例外クラス(unchecked exceptions classes)」
のことを指しています。

なお、ちょっと端折って質問を書いたのですが、NumberFormatException 自体というよりは、
java.lang.Integer.parseInt や java.lang.Double.parseDouble の挙動が
どうあるべきかということを気にしています。
いまさら現実の API 仕様を変えようという気はないのですが、
どうあるのが望ましいか、ということを気にしています。

みなさまのご回答をいただいていろいろ考えたのですが、
パースするときに、フォーマット検査までせざるを得ない、
というようにオペレーションが不可分であることが大きな要因だと考えています。
そして、parseInt/parseDouble が正しいと認めるフォーマットが、API リファレンス、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/lang/Integer.html#parseInt(java.lang.String,%20int)
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/lang/Double.html#parseDouble(java.lang.String)
を見ても完全に特定できるのかどうかが良く分からない(私は分からないです)し、
たとえ特定できたとしても、
そのようなチェックを parseInt/parseDouble を呼ぶ前に別途おこなうのは
至難のワザだと考えます。
したがって現実的なソリューションとしては非チェック例外である NumberFormatException を catch せざるを得ないが、
非チェック例外を catch するのは忍びないということです。


#以下、あとで追加。
引用に対する私の回答が的外れになってました。
やはり NumberFormatException は、コーディングによりそれを「発生しないことを保証できる」から
catch しないほうが良いのでしょうか。
でも、その保証のための事前のチェックが大変です、というのが上記になります。
では、便利ならば catch しまくりでも良いのか。といっても他の非チェック例外、
たとえば ArrayIndexOutOfBoundsException なども catch するのは忍びないです。

[ メッセージ編集済み 編集者: unibon 編集日時 2003-11-17 17:10 ]
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2003-11-17 17:17
こんにちは、Wataです。

私もNumberFormatExceptionはチェック例外であったほうが望ましいと思いますね。
java.text.ParseExceptionがチェック例外であることからも、理にかなっていると思います。

NumberFormatExceptionが非チェック例外であるからには、boolean Integer.canParseInt(String)のようなメソッドがあってしかるべきだと思います。

実際にはそのようなメソッドは存在しないので、でくのぼう氏の言うようにCharactor.digit()でチェックしようと考えます。しかし、値域のチェックや、指数表現の解析まで行うとそれなりの量の処理になりますし、下手するとチェックが終わる前に値が求まってしまいます。また、これだけの処理を記述すればバグの入り込む余地はいくらでもありますし、こんな低レベルな処理を毎回記述しなければならないというのも馬鹿な話です。

というわけで、『自分でチェックするよりNumberFormatExceptionをキャッチしたほうが早い』となるわけで、unibon氏のような苦悩が生まれるのだと思います。

私の見解としては、NumberFormatExceptionが非チェック例外である理由は、初心者への考慮の一部だったのではと考えます。つまり、NumberFormatExceptionがチェック例外であった場合は、たかが『コマンドラインから数値を2つ読み込み、足し算をして結果を出力するだけのプログラム』にも例外処理の知識が必要になり、java入門の障害になると考えたのではないかと思います。

(私はアクセス修飾子の省略なども初心者対処の一部だと考えています。 でもほんとにそんな試みがあったのか、またあったとした場合の有効性があるのかについては知りません )

現状への別解としては次のようなものがあると思いますが、
どれが一番というものでもないような気がします。
  • チェック例外としてのNumberFormatExceptionを投げる。
  • boolean値を返す検査メソッド(canParseInt()など)を用意する。
  • 戻り値をラッパー型にして、パーズ失敗時はnullを返す。(例外は投げない)


# 誤字訂正

[ メッセージ編集済み 編集者: Wata 編集日時 2003-11-17 17:52 ]

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