nekoTheShadow’s diary

技術ブログとして始めたはずが、読書&愚痴ブログになりました(´・ω・`)

Joshua Bloch『Effective Java 第3版』(丸善出版)を読んだ。

Effective Java 第3版

Effective Java 第3版

Javaプログラマの必携書として名高い『Effective Java』の新版である第3版の日本語訳が発売されたということで、さっそく買って読みました。第2版は2008年出版で、Java6を対象としていましたが、それ以降もJavaにはさまざまな機能が追加されてきました。『Effective Java』はいわば「Javaプログラミングのベストプラクティス集」といった位置づけですが、Java6以降に追加された機能の中には、その"ベストプラクティス"のありようをかえてしまったものもあります。第3版は原則として第2版の内容を踏襲しつつ、そうしたJavaの進化に伴って一部修正&大幅追加するというスタンスのもと執筆された--と個人的には理解しました。

Javaプログラマであれば読まないという選択肢はない、というと過言ですが、少なくとも読んで損はない内容であると思います。ジュニアプログラマにとっては新しい知識の源泉であり、シニアプログラマにとっては、ふだん無意識的・経験的に実践しているテクニックを整理して言語化するきっかけになるはずです。前述したとおり、第2版とは内容的な重複がかなりあるため、第2版とは違う斬新な内容を期待していると、期待外れということになります。そこだけは注意しましょう。

実は第2版は読んだことがあり、そのときの読書記録をこのブログの記事として残しているのですが、第2版に比べるとフォントのサイズが大きくなって、読みやすくなっているような気がします(勘違いだったらごめんなさい)。また紙の質も第2版よりやや良くなっている、具体的にはより明るい白で、かつ1枚あたりの重さが軽くなっているように思います(これも勘違いだったらすみません)。内容はともかく、物理的な読みやすさは第3版のほうがよかったような。

さて以下は本書を読みながら残していた読書メモ(というか日記)を整理したものになります。よかったらどうぞ。


第2章 オブジェクトの生成と消滅

  • 項目5 資源を直接結び付けるよりも依存性注入を選ぶ
  • 項目8 ファイナライザとクリーナーを避ける
  • 項目9 try-finallyよりもtry-with-resourcesを選ぶ

第2版と比べて、追加・変更があったのはこのあたりかしらん。項目5については「その通り」のひとことで、本書にも書かれてはいますが、依存性の注入を利用すると、手スタビリティが上がるのが個人的には大きい。また項目9も禿同(←古い)で、try-withy-resoucesはぜひ使いましょう。ただ意外にベテランを自称しているプログラマほど知らなかったりする。

Javaプログラマにとってガベージコレクションとは「確実にそこに存在し、機能を果たしているが、いつ・どこで・どのように動いているかはわからない」という、いわば神がかり的な存在です。よってその「神がかり的な」動きに依存するファイナライザを利用すべきではなく、ましてやその存在をコントロールしようとするなど、もってのほか。ちなみにJava9からfinalizerがdeprecateになったのは本書で知りました。

第3章 すべてのオブジェクトに共通のメソッド

Objectに定義されていて、自作クラスでオーバライドする類のメソッドに関する章。この章は本書でいうところの「一般契約」の解説が中心で、「一般契約」はJavaのバージョンが少し上がったぐらいではほとんど変わらないということもあり、第2版とほとんど違いがないように感じました。

Javaプログラマとしては当然知っておくべきですし、わたしも本書(第2版)を読んで知ったのですが、現実のプログラミングではIDEの機能やLombokなどのライブラリで自動生成することが多い。というか、そのほうが安全なので。

第4章 クラスとインターフェイス

この章で第2版から増えたのが「項目21 将来のためにインターフェイスを実装する」。Java8からインターフェイスにデフォルトメソッドを持たせることが可能になりましたが、項目21はそれを注意して利用するよう警告する項目になります。そもそもデフォルトメソッドの導入により、本章全体の記述が第2版とは変更になっているように思えます。デフォルトメソッドのおかげで、抽象クラスや継承それ自体のプレセンスが下がっている--はずですが、Java6のレガシーシステムをお守りしている自分には関係がなかった(´;ω;`)ウゥゥ

ちなみに第2版を見たところ「項目21 戦略を表現するために関数オブジェクトを使用する」が本章からなくなっているようです。これはいうまでもなく無名関数・ラムダに代替されたからでしょう。

第5章 ジェネリクス

現代的なプログラミングにおいて、ジェネリクスを積極活用しない理由はないと考えています。ジェネリクスというとコレクション関係(ex. List<String>)がまず頭に思い浮かぶのですが、メソッド定義の際に利用すると、型安全でかつ柔軟なAPI設計ができるので、機能をよく把握し、積極的に使いたいと思います。ちなみに第2版から増えたのが「項目32 ジェネリクスと可変長引数を注意して組み合わせる」。ここは@SafeVarargsアノテーション周りのお話ですね。

第6章 enumアノテーション

この章は第2版と比べて、大きい変更なしだと思います。第2版が依拠していたJava6と第3版が依拠しているJava9の間で、enumについては大きな機能追加などはなかったのかな。しかしその裏を返せば、機能追加が不要なほど、enumが強力だということ。enumはシンプルな機構に見えて、工夫次第でいろいろ使える便利屋さん。本書でもいくつも紹介されている--というより、わたしは本書を読んでenumの強さを知ったくちです。

アノテーションについては、もう少し記述があってもよいような気がします。現代的なプログラミングでは何かしらのフレームワークを利用することが多いと思いますが、「アノテーションを使わないJavaフレームワークは存在しない」というほど、アノテーションは多用されます。要するに現代Javaプログラミングとアノテーションは切っても切り離せない関係にあるわけで、それだけの重要性を持つにも関わらず、アノテーションについて扱っている項目が3つだけというのは少し寂しい。

第7章 ラムダとストリーム

第2版と第3版でもっとも大きく変わったのはこの章、というよりこの章自体が丸々追加されています。内容はというと以下の通り。

  • 項目42 無名クラスよりラムダを選ぶ
  • 項目43 ラムダよりもメソッド参照を選ぶ
  • 項目44 標準の関数型インターフェースを使う
  • 項目45 ストリームを注意して使う
  • 項目46 ストリームで副作用のない関数を選ぶ
  • 項目47 戻り値型としてStreamよりもCollectionを選ぶ
  • 項目48 ストリームを並列化するときは注意を払う

はっきりいうと、この章についてはさほど意外性がなかった、というか「関数型プログラミングの世界ではごく当たり前に言われていることが書かれているだけ」という印象を持ちました。ただ「Schemeを中心としてLISP系言語に集中的に取り組んだことがある」「関数型言語の影響が強いRubyを数年にわたって書いている」など、関数型プログラミングに親和的なバックボーンがあるために、余計にそういう感想を持ったのかもしれません。一般的なJavaプログラマは手続き型に慣れているはずで、そういう人に関数型のいろはをJavaの世界に落とし込みつつ、整理して紹介することには大きな意味があるはずです。

第8章 メソッド

「項目55 オプショナルを注意して返す」が追加されていますね。戻り値としてオプショナルが返ってきた場合、メソッドを呼び出した側はこれをある種の異常と受け取るわけですが、Javaではそのような異常を示す際には例外を使ってきました。つまりメソッドを設計するにあたって、オプショナルを返すべきか、あるいは例外を投げるべきかは頭の痛い問題です。

第9章 プログラミング一般 / 第10章 例外 / 第11章 並行性

この3章については第2版との間で大きな変更はないように感じます。もっとも変更がなかったからといって、重要度が低いというわけではなく、単に機能的な変更が少なかったからというだけで、大切な内容が含まれています。

  • 第9章: 「プログラミング一般」というタイトルですが、Java特有の内容も一部含まれています。とりわけ他言語からJavaへ移ってきたプログラマ、そもそもプログラミングに触れ始めたばかりの初心者などは読んで損はない内容だと思います。
  • 第10章: 例外の取り扱いはとにかく難題。しかもJavaには検査例外/非検査例外という、ただでさえ論争的な例外の扱いをさらにややこしくする概念が導入されており、とにかく頭が痛い。本書が示している例外の取り扱い方針はJavaの原理原則に基づいたもので、そういう意味ではまっとうな内容であるといえる--のですが、現実のプログラミングでは基本的に非検査例外を使えばよいと思ったり思わなかったり。
  • 第11章: Javaは意外にマルチスレッドプログラミングに関する機能が充実している一方、慣れていないプログラマ(←わたしのこと)が安易に利用して問題を引き起こしがち。この章はJavaにおけるマルチスレッドプログラミングの機能を紹介したものというよりは、マルチスレッドプログラミングにおけるベストプラクティスを整理したもので、かみしめるように読みました。「項目82 スレッド安全性を文章化する」← とくにこれは実践していこうと思います。

第12章 シリアライズ

シリアライズに深くかかわるようなシステムにかかわったことがなく(せいぜいIIOP程度)、本章は字面だけ読んで終わりとしました。ごめんなさい🙇。この章はシリアライズにおける「べき論」を整理したものだと理解しているのですが、個人的にはこの項目を心にとめておこうと思います: 「項目85 Javaシリアライズよりも代替手段を選ぶ」。年季の入ったシステムならともかく、これから構築するようなシステムであれば、インターフェイスJSONXMLCSVでいいよね……だめ?(´・ω・`)