argius note

プログラミング関連

Java Puzzlers - Joshua Bloch, Neal Gafter

ASIN:4894716895 翻訳は"Effective Java"と同じ柴田さん。

Javaユーザとしては定番ですが、何となく読まずに居たら、随分年月が経ってしまいました。最近、書店で見かけたので読みましたが、もっと早く読んでおくべきだったなと思いました。ちょっとくやしい。

副題に「罠、落とし穴、コーナーケース」とあるように、様々な環境と比較して落とし穴が非常に少ないと言われるJavaの、少ないけど嵌ってしまうかもしれない問題を、パズル形式で解説してくれます。
"Effective〜"では最初にアドバイスなどを告げてから、詳細の解説に入っていくスタイルですが、こちらはまず読者に考えさせる所から始まって、アドバイスや警告が最初は分からないようになっています。実用性は"Effective〜"よりも高いかもしれませんが、参考書のスタイルとしては変化球のようなので、"Effective〜"の次に読むのが良いかと思います。
出題順はカテゴリで分類されているので、ある程度は見当が付くものもあって、思ったよりは当てられたかな。もしこれが章で分類されずにランダムに出題されていたら、おそらく難易度が上がるのではないでしょうか。

(これ以降は、ネタバレを多少、含みますので、未読の方はご注意ください。)


本書で挙げられている問題には、明らかにコーナーケース(#17とか)と言えるものもありますが、現実に問題になるようなケースも結構ありました。大雑把に言って、半数は静的解析ツール(ここではFindbugsとPMD)で発見できるものです。では、ツールで発見するのが比較的容易なものと困難なものは何でしょう。私が調べた限りでは、前者はイディオムとメソッド・シグニチャに関する問題。後者は、プリミティブ数値型の暗黙の変換です。
内部クラス、無名クラス、スレッド、リフレクションについては、ある程度はgrepでも発見できるし、ちゃんと理解しないうちは使わせないという運用もアリかと思うのですが、数値型の問題は見つけづらい上に回避するのも容易ではありません。もちろん、仕様を正しく知っておくことに越したことは無いのですが、精度が落ちる以外の変換はチェックしてくれないので厳しいですね。


今まで見たことがある問題のうち、暗黙のオーバーフローが最も辛いです。オーバーフローして負の数になったのに何も言ってくれないなんて。自分で書いているなら気づくことができますよ。例えば、System.currentTimeMillis()の値と比較するためにこんな計算をしていました。

int x = 30 * 24 * 60 * 60 * 1000;

最初に、型がintなこと。次に、"* 1000"でInteger.MAX_VALUEを超えること。最後に、"30"はプロパティで可変になっていたこと。当初は"15"でした。下記のように直しました(実際のコードとは全く違います)が、Calendarクラスを使うのが正解かな。

Integer propDays = Integer.getInteger("days"); // 15から30に変更
int days = (propDays == null) ? 0 : propDays.intValue();
long milliSeconds = 1000L * 60 * 60 * 24 * days;

あと、自分もやってしまったことがあるものとしては、Comparatorの戻り値に整数の差を利用するというもの。大抵は上手くいくし、実際、値の範囲が狭かったので今でも上手くいっているのでしょう、きっと。

3つ目も、intのアンダーorオーバーフロー関連。これは「やっちゃった」ではなくて、なるほどー、と思ったもの。ちゃんと勉強した方にとっては常識かもしれませんが、この本を読むまで知りませんでした。絶対値が同じになる値は、正と負でペアになっていますが、0と-0は内部では同じ値。int型は2の32乗の組み合わせなので、1つ仲間外れが出ます。

他には、使えないと思っていたけど、コードレビューをしていて見つけて、気になって調べてみたら、っていうのが「短絡評価ではない」論理演算。

String s = null;
if (s != null & s.startsWith("A")) System.out.println(s);

nullでないことを確認しているのに、結果に関わらず右辺も評価されてしまいます。幸い、これはFindbugsが見つけてくれます。メッセージの意味を理解するのに苦労するかもしれません。


他にもたくさんありますが、後は実物に任せます。

静的解析は難しいかもしれませんが、完全に解析できなくても、数値の計算をしているところを探して、後は人間が部分レビューするというのが現実的でしょうか。これを実施するために、近いうち、独自ルールの追加に挑戦してみようかと思っています。

余談1

なぜJavaの公式サイトには英語以外に日本語しかないのか、というのを誰かが「日本人は志が低いから(全然違ったかも)」って批判(?)してたのを読んだことがあって、それが無意識下で何だかもやもやしていたのです。
が、本書のまえがきで「日本のJavaコミュニティーは初期の頃から最も熱心なサポーター」というお言葉により、英語圏のJava愛好家の次に日本語圏の愛好家が多い可能性もあることを認識。
どちらが正しいかどうかではなく、自分の思考が如何に柔軟じゃないかを。

余談2

この本に錯視図を提供している北岡教授が出演されたテレビ番組を昨日たまたま見ました。ちらっとだけですが。