- PR -

文字列をequalsで判定する時

投稿者投稿内容
OTAKE
会議室デビュー日: 2008/02/08
投稿数: 18
投稿日時: 2008-02-13 23:26
引用:
nullの場合にNullPointerExceptionを発生させなくてはならなくて、
かつ、引数の文字列を参照しないケースってどんな場合なのでしょうか?
使わないならそもそも引数に渡さないでしょ。


例えば、HttpServletRequestのgetHeader()の戻り値で処理を分岐する場合、getHeader()でnullが返ってくる可能性はあるけど、処理の中では使いませんよね。
で、正しく実装された画面からのリクエストなら、getHeader()がnullを返すことはないので、getHeader()の返り値がnullの場合はエラー処理をする必要があります。

まあ、あくまでも一例ですけどね。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-02-13 23:50
HTTPヘッダで定数と比較する処理なんて書くかな?
Accept-Languageとかでも重みづけとかあるからパース処理が必要だし。

個人的に定数を左に置いたがゆえに例外が隠されてバグとなった
という事象に遭遇したことがないので、具体的な事例が知りたいところですね。

すべての経路を正しく網羅してテストする自信のある方はNullPointerExceptionが
出るケースをデバッグ時に完全に取り除けばいいんじゃないでしょうかね。

私は、完全なテストをする自信がなく、かつ、定数を左に置いた際に
問題になると言われている例外隠しによるバグに遭遇したことがないので
定数を左に置くほうがマシかな、程度に考えています。
なんというか、例外隠しが発生するといわれる状況って前提が成立するのかなぁ…。

この辺も、どこに重きを置くかという価値観による話なのですけども。

ついでに言えば、Eclipseの場合、未使用引数のチェックは標準で行えますが、
NullPointerのチェックはFindBugsでも導入しないと行えない。
しかも常時チェックするには重いんですよね。コレ。
そんなわけで、未使用変数の検出が容易に行える現状では定数を左に置く
デメリットってそれほど目立たないとは思っています。

ま、変数を左にしてもFindBugsで検出すれば網羅的に探せるんで程度問題ですよ。
OTAKE
会議室デビュー日: 2008/02/08
投稿数: 18
投稿日時: 2008-02-14 00:06
引用:
そんなわけで、未使用変数の検出が容易に行える現状では定数を左に置く
デメリットってそれほど目立たないとは思っています。


コードを読む人にとって読みにくいというデメリットは無視しての話ですね。
ま、「私に」とっては読みにくくないと言われると、「そうですか」としか言えませんが。

引用:
ま、変数を左にしてもFindBugsで検出すれば網羅的に探せるんで程度問題ですよ。


その程度の軽い問題だと思うなら、そこまで一生懸命に反論しなくてもいいんじゃないですか?
誰も、B派は異端だからA派に改宗しろなんて強制していないわけですし。
それにどんな理由を述べたところで、
引用:
個人的に定数を左に置いたがゆえに例外が隠されてバグとなった
という事象に遭遇したことがない


なんて言われたら、説得する言葉もないわけで。

定数を右に置く人にしても「個人的に定数を右に置いたがゆえに例外が隠されてバグとなったという事象に遭遇したことがない」は成立するわけで、主張するだけ無駄なことですよね?
となると、バグ発生率は優劣の差にはならなくて、読みやすさ/にくさが問題になってくるわけです。
nagiseさんも最初の発言では、読みやすいから"hoge".equals(str)を使うとは言っていないわけで。
OTAKE
会議室デビュー日: 2008/02/08
投稿数: 18
投稿日時: 2008-02-14 00:19
未記入だと紛らわしくなったので、ハンドルを変更します。
ほとんどの人にとってはどうでもいいことだと思いますが。。。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-02-14 00:56
引用:

OTAKEさんの書き込み (2008-02-14 00:06) より:
コードを読む人にとって読みにくいというデメリットは無視しての話ですね。
ま、「私に」とっては読みにくくないと言われると、「そうですか」としか言えませんが。


まさに私にとってはなんら読みにくくはないですから。

プログラミングの理解の過程で、読みにくく思える可能性はあるとは思います。
それが、先に私が書いたように「"hoge"をオブジェクトとして捉えられるか?」
という話題になるわけです。ただ、オブジェクトとして捉えるかどうかが
読みやすい、あるいは気持ち悪く思わないの条件ではないかという私の説は、
同意を得られなかったのも事実ですね。

そのことから、この点は主観の域を出ないので議論する余地がなくなってしまっています

引用:

引用:
ま、変数を左にしてもFindBugsで検出すれば網羅的に探せるんで程度問題ですよ。


その程度の軽い問題だと思うなら、そこまで一生懸命に反論しなくてもいいんじゃないですか?


私も強制する気はなく派閥なんか関係ないという立場です。
自分は、発生するメリット、デメリットについて一歩踏み込んで理解したいと思っている。
それが、自分がすんなりと納得できない説に対して対案を出す理由。
軽い問題だからこそ、何派とかいう立場なんか抜きに議論ができるんでしょう?

知的好奇心を満足したいから議論しているのであって、自分の立場とかは関係ない。
軽い問題をまじめに議論していることが、その証明だと言えませんか?


引用:

引用:
個人的に定数を左に置いたがゆえに例外が隠されてバグとなった
という事象に遭遇したことがない


なんて言われたら、説得する言葉もないわけで。


これはやり込めようという意図はまったくないことをご理解いただきたい。
具体的に問題となるケースが挙げられないまま、「問題があるから
やめたほうがいいんじゃないの?」という議論は続かないでしょう?


問題があるなら具体的にどういうケースで問題となるのかを正しく把握したい。
そうすることで、その後のことが考えられる。
つまり、「どうしたら、その問題を超えられるか?」という話題。
あるいは、その問題が重大なら、定数を前に置かないことで解決を試みるかもしれない。

引用:

定数を右に置く人にしても「個人的に定数を右に置いたがゆえに例外が隠されてバグとなったという事象に遭遇したことがない」は成立するわけで、主張するだけ無駄なことですよね?


ここはちょっと解説しておかないといけないでしょうね。

まず、変数を左に置く場合。str.equals("hoge")の場合は、
nullの考慮漏れはそのままNullPointerExceptionを発生させる。

RuntimeExceptionというのは、障害があって継続が不可能な場合に、
できるだけ速やかにその障害を報告するためにある。
だから、NullPointerExceptionが検出できるじゃないか!という主張は
まるで問題がないといえましょう。私もその点は異論がない。

変数を左とした場合は、常にnullの考慮を行わなくてはならないことは
ここまでの話で出ていますね。
もし、仕様としてNullPointerExceptionをthrowするならば、冒頭でnullをチェックして
Exceptionを明示的にthrowすべき
というのは同意の取れている事項でしょう。
このことから、このチェックなしに単体でstr.equals("hoge")という表記がある場合
それは「ありえないコード」であることから考慮漏れからくるバグと想定される


そして、その考慮漏れの大半の場合は変数がnullの場合は"hoge"とのequalsの結果が
単にfalseとなる場合
でしょう、という指摘も挙がっていましたね。
そうすると、この習慣からプログラミング時にNullPointerExceptionを盛り込む確率は高くなるが、
それは単にequalsで得たかった結果、つまるところfalseを導き損ねているだけだと。
ただ、それはデバッグ時に確実なテストを行えるなら検出可能だから問題とならないとされていますね。
私は確実なテストを行える自信がないことも先に述べました。

さて、定数が左の場合、つまり"hoge".equals(str)という場合、この大半のケースにおいては
そもそもバグとはならず、意図どおりの挙動を示すプログラムとなる

つまり、プログラミングの段階でバグを盛り込む可能性は減る。
テストでの検出漏れを危惧するなら、そもそもバグが作り込まれないにこしたことはない。
しかし、大抵の場合はよいとしても、レアなケースではより検出しにくいバグを
作り込むのではないか
、という話になっているわけです。

ですから、"hoge".equals(str)の場合のみ例外隠しが問題として挙がるわけで、
str.equals("hoge")での例外隠しなどそもそも議論の俎上に上がらないわけです。
str.equals("hoge")は例外をばんばん出すことは同意事項でしょう?

だから、読みやすさの議題にはならないのですよ。
"hoge".equals(str)は例外を隠すというけど、実際にどういうケースがあるの?と。
そういう流れで議論がされている。
このあたり、ご理解いただけるでしょうか。
OTAKE
会議室デビュー日: 2008/02/08
投稿数: 18
投稿日時: 2008-02-14 01:28
引用:
"hoge".equals(str)は例外を隠すというけど、実際にどういうケースがあるの?と。
そういう流れで議論がされている。


という話なので、実際に例を挙げてみたところ、
引用:
HTTPヘッダで定数と比較する処理なんて書くかな?


と設計のよしあしに話を摩り替えられたわけです。
で、この人にはどんな例を出しても、話を摩り替えて自説を述べるしかしないのだなと諦めただけです。
引用:
まさに私にとってはなんら読みにくくはないですから。


何度も、ほかの人が見る可能性を考えましょうと言っているのですが、理解してもらえないのですね。
引用:
知的好奇心を満足したいから議論しているのであって、自分の立場とかは関係ない。
軽い問題をまじめに議論していることが、その証明だと言えませんか?


であるならば、このような発言はしてほしくなかったですね。
引用:
AでもBでもいいですが、NullPointerの考慮漏れのバグは作りこまないで欲しい。


本人は深い意味も考えずに発言したのかもしれませんが、A派では考慮漏れのバグを作りこむだろうと、読み取れます。

純粋に議論したいならば今後も付き合いますが、自説を押し通したいならご遠慮します。

未記入
大ベテラン
会議室デビュー日: 2008/02/07
投稿数: 115
投稿日時: 2008-02-14 02:04
引用:

しかし、大抵の場合はよいとしても、レアなケースではより検出しにくいバグを
作り込むのではないか、という話になっているわけです。

ですから、"hoge".equals(str)の場合のみ例外隠しが問題として挙がるわけ


ここまでは良く分かる。私もこれまで nagise さんの意見には同意だし。

引用:

"hoge".equals(str)は例外を隠すというけど、実際にどういうケースがあるの?


でも、これはなんだかねえ。OTAKE さんが例を挙げても「そんな処理なんて書くかな?」とか反論にもなってないような反論しているのはどうかと思う。

私も "hoge".equals(str) が例外を隠してしまうケースは、それなりにあると思う。すぐに実例は思いつかないのだけど… else 節を使うことってあるよね。

コード:
	if("hoge".equals(str)) {
		...
	} else {
		...
	}



このようなコードの場合、str == nul なら else 節が処理されることになるけど、開発者は null について考慮していないだけで「null ならどちらの処理もしたくなかった」というケースはあるんじゃないかな。

私は null が与えられても false が返れば十分というときにしか、上記の記述をしないから、こんな間違いをすることはないけれど、規約で決められているとか、記述の統一とか言って常に "hoge".equals(str) と書いている人達は、null のときに else 節に処理が移ってしまった!という人もいるんじゃないかと予想。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-02-14 02:10
引用:

OTAKEさんの書き込み (2008-02-14 01:28) より:
引用:
"hoge".equals(str)は例外を隠すというけど、実際にどういうケースがあるの?と。
そういう流れで議論がされている。


という話なので、実際に例を挙げてみたところ、
引用:
HTTPヘッダで定数と比較する処理なんて書くかな?


と設計のよしあしに話を摩り替えられたわけです。
で、この人にはどんな例を出しても、話を摩り替えて自説を述べるしかしないのだなと諦めただけです。


現実的にHTTPヘッダを定数と比較することはないだろう、という指摘に対して「ある」というならそれを示せばよいではないですか。
「こういうケースはどうでしょう?」「でもそれって成り立たなくない?」「それは話のすり替えだ!」では文字通り話になりません。
私は実際にはHTTPヘッダで定数と比較することはないんじゃないの?と言った。
それは、自説を押したいからではなく、それが事実だと思うからです。
いや、定数と比較することはあるよ!というならそれを出してください。
私はそれを知りたい。自分では「ない」と思っている事項をやる例があるなら知りたい。
ぜひ挙げて欲しい。

一応、私のほうでHTTPヘッダで一般的なものを調べたんですよ。
過去に自分で定数とHTTPヘッダを比較することがあったかなぁ、と思い返しながら。

Accept、Accept-Charset、Accept-Encoding、Accept-LanguageといったAccept系は
先にあげたようにq値による重みづけがあるので、定数との比較はできない。
Authorization、Proxy-Authorizationもユーザ・パスワードが付加されるので定数との比較はできない。
Fromはメールアドレスが渡されますが、現在では使われないし定数との比較はしない。
Hostはバーチャルホストっぽいことをするなら読むかもしれないけど、
そもそもTomcatとかのバーチャルホスト機能を使うだろうから通常は定数との比較はしない。
If-Modified-Since、If-Unmodified-Sinceは指定時刻以降の変更を知るものだけど、時刻をパースする
必要があるから定数との比較はできない。
If-Match、If-None-Matchも条件付きリクエストですから定数との比較は通常しないだろう。
If-range、Rangeはダウンロードのレジュームなどで使われるけど、数値が渡されるから定数との比較はしない。
Max-Forwardsも数値を解釈する必要があるから定数との比較はしない。
Refererは参照元だけど、統計情報とすることが多い。
もしかしたら特定のURLからのアクセス以外をはじく場合に定数と比較するかもしれない。
でも、そこってハードコーディングするのだろうか?
User-Agentは可能性として定数比較する可能性がわずかにある。
しかし、ブラウザが返す文字列はバージョン情報も含まれるし、
どうにも一定しないのが実際だから、単純な定数との比較は現実的ではないだろう。

以上のように、「実際に定数と比較するシチュエーションが考えにくい」という
考察をして発言しているわけですよ。
それを「自分がそういう使い方をするといったらするんだ!」と主張されても困る。

引用:

引用:
まさに私にとってはなんら読みにくくはないですから。


何度も、ほかの人が見る可能性を考えましょうと言っているのですが、理解してもらえないのですね。


ですから、「私」というのは一個体のサンプルであって、
私に限らず「読みにくいとは思わない」という人がいるわけですよ。
そして、場合によっては
コード:
if (str != null && str.equals("hoge")) { ...} // A
if ("hoge".equals(str)) { ...} // B


とあった場合に、Aは冗長でBのほうがすっきりして読みやすいという人もいる。
それも考慮して「ほかの人が見る可能性」を考えるべきでしょう。
そして、どちらが読みやすいという客観的な結論が出ない以上、
他の人が見る可能性を考慮したとしても、
「読みやすい人もいるだろうし、読みにくい人もいるかもしれない」
としか言えない、と言っているわけです。
それが、読みやすさを議論の対象とできないという理由。
主観以上の理由がないでしょう、と。

引用:

引用:
知的好奇心を満足したいから議論しているのであって、自分の立場とかは関係ない。
軽い問題をまじめに議論していることが、その証明だと言えませんか?


であるならば、このような発言はしてほしくなかったですね。


どのような発言ですか?

引用:

引用:
AでもBでもいいですが、NullPointerの考慮漏れのバグは作りこまないで欲しい。


本人は深い意味も考えずに発言したのかもしれませんが、A派では考慮漏れのバグを作りこむだろうと、読み取れます。


どう読んだらそう読めるのですか?

Bでもifの条件式のその場ではNullPointerExceptionが出ないかもしれないけども、
throwすべきところでthrowしなければNull Pointerの考慮漏れのバグになるでしょう?
そこは一切否定していない。Bでもnullの考慮漏れはある。
nullのときはfalseとすればよい状況でコーディングミスによるNullPointerExceptionは
防げるのではないの?とは確かに言っているけども。

引用:

純粋に議論したいならば今後も付き合いますが、自説を押し通したいならご遠慮します。


はい。
私も純粋に議論したいならば今後も付き合いますが、自説を押し通したいならご遠慮します。

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