Effective JAVA 第2版

このページはEffective JAVAを読んだメモを書きます。
なお、管理者の文章力があれだったりページ作成中ということもあり、いろいろ間違っている可能性があります。
間違いが起こらない為にも購入して読まれることをおすすめします(宣伝)
Amazonのリンク↓

Effective JAVA 概要

Effective JAVAはプログラミング言語Javaについて、
より良いプログラムの書き方についてまとめられた本です。

Effective JAVAは以下の章で構成されています。
 第1章 はじめに
 第2章 オブジェクトの生成と消滅
 第3章 すべてのオブジェクトに共通のメソッド
 第4章 クラスとインタフェース
 第5章 ジェネリックス
 第6章 enumとアノテーション
 第7章 メソッド
 第8章 プログラミング一般
 第9章 例外
 第10章 並行性
 第11章 シリアライズ

第 1 章 はじめに

Javaは正式なリリース名と、それに対応するエンジニアリングバージョン番号を持つ。し、知らなかった…
正式なリリース名 エンジニアリングバージョン番号
Java Platform, Standard Edition 6 1.6

Java言語は4種類の型をサポートしている。これを知っていればJava通を名乗れる(嘘)
 ・インターフェース
 ・クラス
 ・配列
 ・基本データ

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

項目 1 コンストラクタの代わりに static ファクトリーメソッドを検討する
クラス設計時の話。publicのコンストラクタ以外にpublicのstaticファクトリーメソッドを提供できる。
staticファクトリーメソッドとは、クラスのインスタンスを返すstaticのメソッドである。

staticファクトリーメソッドの長所
  • メソッド名を持つ
  • メソッドが呼び出されるごとに新たなオブジェクトを生成する必要がない
  • メソッドの戻り値型を任意のサブタイプのオブジェクトで返すことができる
  • パラメータ化された型のインスタンス生成の面倒さを低減する
staticファクトリーメソッドの短所
  • public,protectedのコンストラクタを持たないクラスのサブクラスを作れないこと
→☆よく分からないので再読。
  • 他のstaticメソッドと区別がつかない
→ドキュメントで注意を引いたり標準の命名規約に従うことで対処する。

項目 2 数多くのコンストラクタパラメータに直面した時にはビルダーを検討する
コンストラクタやstaticファクトリーメソッドは、パラメータをたくさん持つのに不向きである。

テレスコーピングコンストラクタパターンは必須パラメータだけを受け取るコンストラクタと
+αのオプションを受け取るコンストラクタを複数作成する。
オプションパラメータが多すぎると大変なことになる。

JavaBeansパターンはパラメータなしのコンストラクタを呼び出し
必要とされるオプションのSetterメソッドを呼び出す。

呼び出しが複数の記述に分断されるため、
誤ったパラメータを渡した場合に不具合を検知し難いという欠点ある。
これは本書を読んで初めて知った。そう言えばそうだね。

両者の欠点を克服したものがビルダーパターンである。

項目 3 private のコンストラクタか enum 型でシングルトン特性を強制する
シングルトンの実装方法
  • public finalのフィールドによるシングルトン
  • staticファクトリーメソッドによるシングルトン
  • enumシングルトン
項目 4 private のコンストラクタでインスタンス化不可能を強制する
ユーティリティクラスのインスタンスはほぼ意味が無いので
そもそもインスタンス化できないようにする記述が必要。
項目 5 不必要なオブジェクトの生成を避ける
コストが高く用途が決まりきっているオブジェクト(Calendarクラスの特定日付など)は
クラスのstaticフィールドとして据え置き、static初期化子を用いることで
パフォーマンスの改善を図ることができる。
項目 6 廃れたオブジェクト参照を取り除く
Wikipediaより引用。メモリリーク - Wikipedia
メモリリーク (Memory leak)とは、プログラミングにおけるバグの一種。
プログラムが確保したメモリの一部、または全部を解放するのを忘れ、確保したままになってしまうことを言う。

メモリリークが発生する原因でよくある物は以下のとおり。
  • 意図しないオブジェクトの保持
  • キャッシュ
  • リスナーやコールバック
項目 7 ファイナライザを避ける

第 7 章 メソッド

項目 38 パラメータの正当性を検査する
項目 39 必要な場合には、防御的にコピーする
項目 40 メソッドのシグニチャを注意深く設計する
項目 41 オーバーロードを注意して使用する
項目 42 可変長引数を注意して使用する
項目 43 null ではなく、空配列か空コレクションを返す
項目 44 すべての公開 API 要素に対してドキュメントコメントを書く

第 8 章 プログラミング一般

項目 45 ローカル変数のスコープを最小限にする
  • ローカル変数宣言は初期化子を含んでいるべき
  • ローカル変数宣言はできるかぎり使用する直前に行う
forループのイディオム3つ。
   // ①コレクションのイテレート
   for (Element e : c) {
       doSomething(e);
   }
   // ②イテレータを用いたforループ
   for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
       doSomething(i.next());
   }
   // ③ローカル変数のスコープを最小限にするイディオム
   for (int i = 0, n = expensiveComputation(); i < n; i++) {
       doSomething(i);
   }
項目 46 従来の for ループより for-each ループを選ぶ
前述の②③は単なるforループであり余り良くないらしい。
Mapのループはイテレータを使ったforループしかやったことが無かったので
for-eachループはどうやるのかを調べた。
   // ④Mapのイテレート
   for(Map.Entry<String, String> e : map.entrySet()) {
       doSomething(e.getKey());
       doSomething(e.getValue());
   }

for-eachループが使えない状況
  • フィルタリング
  • 変換
  • 並列イテレーション
項目 47 ライブラリーを知り、ライブラリーを使う
プログラマは以下の標準ライブラリーの内容を知っておくべき。
  • java.lang
  • java.util
  • java.io
  • java.utilパッケージのコレクションフレームワーク
  • java.util.concurrent
項目 48 正確な答えが必要ならば、float と double を避ける
扱うデータとそれに対応するデータ型
  • 9桁以下の整数 -> int
  • 18桁以下の整数 -> long
  • 18桁を超える -> BigDecimal
  • 小数を含む -> BigDecimal
項目 49 ボクシングされた基本データより基本データ型を選ぶ
  • 基本データ型(primitive type)→ int, double, boolean
  • 参照型(reference type)→ String, List

対応するデータ型同士は特別な操作なしに代入できる。
   // 自動ボクシング(autoboxing)
   int a = 10;
   Integer b = a;
   // 自動アンボクシング(auto-unboxing)
   Integer c = new Integer(10);
   int d = c;

参照型同士を == 演算子でつなげると値の比較ではなく、
2つのオブジェクト参照に対して同一性比較(identify comparison)を行う。
   Integer first  = new Integer(10);
   Integer second = new Integer(10);
   // first == second // 同じ値を表していても異なるIntegerインスタンスへ参照しているならfalseを返す

☆単一操作内で"基本データ型""ボクシングされた基本データ型"を混在させた場合、
ほとんどの場合に"ボクシングされた基本データ"は自動アンボクシングされる。
   Integer i;
   if (i == 42) { // nullオブジェクト参照が自動アンボクシングされるとNullPointerExceptionがスローされる
       // 到達しない  
   }
項目 50 他の型が適切な場所では、文字列を避ける
データの扱い方の話。
データが本質的に本当に文字である場合にだけ、文字として扱うのが正しい。
データが数値ならば、int, float, BigIntegerなどの適切な数値型を使用すること。
項目 51 文字列結合のパフォーマンスに用心する
String型の(+)による文字列結合はめっちゃ遅いので
StringBuilderのappendメソッドを使う。
項目 52 インタフェースでオブジェクトを参照する
   List<String> list = new Vector<String>();
のListの部分はインターフェース型と呼ぶ。
new の後ろに続くクラスを後から変更しやすい。
項目 53 リフレクションよりインタフェースを選ぶ
本文より引用。
リフレクションの正当な使用方法は、実行時には存在しないかもしれない他のクラス、メソッド、あるいはフィールドに対するクラスの依存性を管理することです。
JavaBeanクラスのフィールド名hoge01~hoge99の一括設定とかでリフレクションを使うのはよくないんだね!
ArrayList使えよという話だけどJavaBeanクラスを渡す先のO/Rマッパーが上手く動いてくれない(泣
項目 54 ネイティブメソッドを注意して使用する
C,C++等Java以外のプログラミング言語で書かれた特別なメソッドであるネイティブメソッド
Java Native Interface(JNI)で呼べるそうです。まず使わない。
項目 55 注意して最適化する
既に稼動しているプログラムはバグや仕様変更が無い限り触らないほうがいい。
項目 56 一般的に受け入れられている命名規約を守る
命名規約で参考になりそうなサイト↓
最終更新:2015年11月13日 00:34