Effective Java 第3版 第9章プログラム一般


Java中級者以上の必須本である、Effective Java 第3版に Kindle版が出たので、まとめる。

前:Effective Java 第3版 第8章メソッド
次:作成中

項目57 ローカル変数のスコープを最小限にする

  • ローカル変数のスコープを最小限にする最も強力な技法は、ローカル変数が初めて使われた時に宣言すること。(ブロックの先頭で初期化しない)
  • ほとんどすべてのローカル変数宣言は、初期化子を含むべき。初期化するのに必要な情報がない場合は、変数宣言を先送りすべき。
  • forループ、for-eachループの両方で、ループ変数を宣言でき、スコープを必要な領域だけに限定する。
for (Element e : c) {
  // eで何かを行う
}

for (Iterator<Element> i = c.iterator; i.hasNext(); ) {
  Element e = i.next();
  // eとiで何かを行う
}
  • メソッドを小さくして焦点をはっきりさせる。メソッド内に二つの処理があるならば、メソッドを分ければスコープは小さくなる。

項目58 従来のforループよりもfor-eachループを使う

for (Suit suit : suits) {
  for (Rank rank : ranks) {
    deck.add(new Card(suit, rank));
  }
}
  • 明快性、柔軟性、バグ予防に関して、for-eachの方が、従来のforループよりも優れている。
  • パフォーマンス上のペナルティがない。
  • for-eachが使えない状況
    • 破壊的フィルタリング・・・要素を削除しながらループするような場合
    • 変換・・・要素の一部や全部を置換する場合
    • 並列イテレーション・・・並列にループするような場合

項目59 ライブラリを知り、ライブラリを使う

  • Java7の時点で、Randomはもはや使うべきではなく、ThreadLocalRandomを使うべき。高品質で速い。
  • 標準ライブラリを使うことの利点
    • 専門家の知識と、前に使った人々の経験を利用できる。
    • 時間を無駄にしない。自分のアプリケーションに時間を費やすべき。
    • 時間とともにパフォーマンスが改善されることがある。
    • 時間とともに、ライブラリには新たな機能が追加される。
    • あなたのコードが大勢の開発者に受け入れられる。

項目60 正確な答えが必要ならば、floatとdoubleを避ける

  • float型double型は、金銭計算には適していない。
    • 正確に0.1を表すのが不可能だから。
  • 金銭計算には、BigDecimal型intlongを使う。
    • BigDecimal型のデメリットは計算に不便で遅い。
      • 代替は、intlongを使い、ドルではなくて、全部セントで計算するなど。
  • intは9桁まで、longは18桁まで、それ以上はBigDecimalを使う。

項目61 ボクシングされた基本データ型よりも基本データ型を選ぶ

  • 基本データ型とボクシングされた基本データや型の違い
    • データ型は値だけを持ち、ボクシングされた基本データのインスタンスは値とは別のアイデンティティを持つ。
    • ボクシングされた基本データは、nullを持てる。
    • 基本データ型は、時間と空間に関して効率的。
  • ボクシングされた基本データに対して、==演算子を適用するのは、ほぼ誤り。
  • ボクシングされた基本データの使い道
    • コレクション内の要素、キー、値。
    • パラメータ化された型とメソッドの型パラメータ。

項目62 他の方が適切な場所では、文字列を避ける

  • 文字型は、テキストを表現するために設計されていて、申し分なくその役割を果たしているが、他の値型に対する代替としては貧弱。
  • もし、適切な値型があればそれが基本データ型であろうが参照型であろうが、その型を使うべき。

項目63 文字列結合のパフォーマンスに用心する

  • 文字列の結合は、項目の数が多い時には、StringBuilderを使う。

項目64 インタフェースでオブジェクトを参照する

  • 適切なインタフェース型が存在するならば、パラメータ、戻り値、変数、フィールドはすべてインタフェース型を使って宣言されるべき。
  • 実装を切り替えたい場合、コンストラクタを指定しているクラス名を変更するだけ。(または別のstaticファクトリメソッドを使う)
  • 適切なインタフェースが存在しない場合、インタフェースではなく、クラスでオブジェクトを参照することは適切。
    • StringIntegerなどの値クラス
    • オブジェクトがクラスに基づくフレームワークに属しているなら、一般に抽象クラスである関連する基底クラスで参照するのが望ましい。OutputStreamといった、java.ioの多くがこの分類に属する。
    • インタフェースは実装しているが、そのインタフェースにはない追加のメソッドをクラスが提供している場合。例えば、comparatorメソッドを持つ、PriorityQueueクラス。ただし、まれであるべき。

項目65 リフレクションよりもインタフェースを使う

  • リフレクションの代償
    • コンパイル時の型検査の恩恵を全て失う。存在しないメソッドやアクセス不可能なメソッドを呼び出そうとするとプログラム実行時に失敗する。
    • リフレクションによるアクセスを行うコードは、ぎこちなく冗長。読むのが難しい。
    • パフォーマンスが悪い。
  • コンパイル時に知られていないクラスと一緒に動作しなければならないプログラムを書くなら、できる限りオブジェクトのインスタンスかのためだけにリフレクションを使い、コンパイル時に分かっているインタフェースやスーパークラスを使ってオブジェクトへアクセスすべき。

項目66 ネイティブメソッドを注意して使う

  • CやC++などのネイティブのプログラミング言語で書かれたメソッドであるネイティブメソッドの呼び出しを、Javaアプリケーションから可能にするのが、Java Native Interface(JNI)
  • ネイティブメソッドの用途
    • レジストリやファイルロックなどのプラットフォーム固有の機構へのアクセスを提供。
    • 既存のネイティブコードへのアクセスを提供しており、レガシーライブラリも含まれる。
    • パフォーマンス改善。
  • JVM実装は速くなってきており、ネイティブメソッドを使うことは勧められない。
  • ネイティブメソッドの欠点
    • 安全ではない。
    • 移植性が低く、デバッグが困難。
    • ネイティブメソッドの呼び出しにはコストがかかり、パフォーマンスを低下させる可能性がある。

項目67 注意して最適化する

  • 速いプログラムよりも優れたプログラムを書くように努める。優れたプログラムを書けば、スピードは結果として得られる。
  • システムの構築を終えたら、パフォーマンスの測定をする。
  • 速くなければプロファイラの助けを借りて、原因を突き止める。
  • publicの型を可変にすると、不必要に防御的コピーを必要とすることがある。

項目68 一般的に受けいられている命名規約を守る

  • 命名規約には、活字的と文法的がある。
    • 活字的命名規約は、ほんの一握りしか無く明確である。
    • 文法的命名規約は、複雑で曖昧。

活字的命名規則

  • パッケージ名、モジュール名
    • ピリオドで区切られた要素を持ち、階層的であるべき。
    • 小文字とまれに数字から構成される。
    • 要素が逆順となった、インターネットドメイン名で始まるべき。
    • 要素は短く8文字以下であるべき。
    • 省略形は推奨されている。
  • クラス名、インタフェース名、enum名
    • 大文字から始まる。(アッパーキャメルケース、パスカルケース)
    • 省略形は避けるべき。
  • メソッド名、フィールド名
    • 小文字から始まるべき(ローワーキャメルケース)
  • 定数フィールド
    • 全て大文字、アンダースコアで区切られる。
    • static final、または不変フィールド
  • ローカル変数
    • メンバー名と同じだが、省略形も許される。
  • 型パラメータ名
    • たいてい1文字。
    • T任意の型
    • Eコレクションの要素型
    • K V マップとキーの値
    • X例外
    • R戻り値

文法的命名規則

  • クラス名、enum名
    • 単数名詞、名詞句
  • インスタンス化できないユーティリティクラス
    • 複数名詞
  • インタフェース
    • able、ibleで終わる形容詞
  • アノテーション型
    • 全ての品詞が使われる
  • 何らかの処理を行うメソッド
    • 動詞、動詞句
    • boolean値を返すメソッドは、is、hasで始まる。
    • boolean値ではないメソッドは、名詞、名詞句、getで始まる動詞句
  • オブジェクトの型を変換し、別の型を返すメソッド
    • toTypeと呼ばれ、toString、toArray
  • レシーバーオブジェクトの型とは異なる型を持つビューを返すメソッド
    • asTypeと呼ばれ、asList
  • メソッドが呼び出されたオブジェクトと同じ値を持つ基本データを返すメソッド
    • typeValueと呼ばれる。intValue
  • staticファクトリメソッドを持つ共通の名前
    • from、of、valueOf、instance、getInstance、newInstance、getType、newType