Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Effective Java 輪読会 項目49-52

1,221 views

Published on

Published in: Technology
  • Login to see the comments

  • Be the first to like this

Effective Java 輪読会 項目49-52

  1. 1. Effective Java 輪読会 第7回 (項目49~52) 2014/2/19 開発部 野口
  2. 2. 項目49 ボクシングされた基本データより 基本データ型を選ぶ
  3. 3. 基本データ型とボクシングされた 基本データ型の 3 つの違い  基本データ型は値だけを持つが、ボクシング された基本データ型のインスタンスは値とは 別のアイデンティティを持っている  基本データ型は完全に機能する値だけを持っ ているが、ボクシングされた基本データ型は null という機能しない値も持っている  基本データ型のほうがボクシングされた基本 データ型よりも時間・空間においてより効率 的
  4. 4. 不完全なコンパレータ <基本データ型は値だけを持つが、ボクシングされた基本データ型の インスタンスは値とは別のアイデンティティを持っている>  first < second では自動アンボクシングされ、うまくいく  first == second では Integer インスタンスの同一性比較を行 う  間違い! Comparator<Integer> naturalOrder = new Comparator<Integer>() { public int compare(Integer first, Integer second) { return first < second ? -1 : (first == second ? 0 : 1); } };
  5. 5. 不完全なコンパレータの修正案 Comparator<Integer> naturalOrder = new Comparator<Integer>() { public int compare(Integer first, Integer second) { int f = first; // 自動アンボクシング int s = second; // 自動アンボクシング return f < s ? -1 : (f == s ? 0 : 1); // アンボクシングなし } };
  6. 6. Integer と int との比較 <基本データ型は完全に機能する値だけを持っているが、ボクシング された基本データ型は null という機能しない値も持っている>  Unbelievable は表示……されません  かわりに、(i == 42) で NullPointerException がスローされます  単一操作内で基本データ型とボクシングされた基本データ型を混在させた場合に は、ほとんどの場合にボクシングされた基本データ型は自動アンボクシングされ る  この場合、i を Integer ではなく int で宣言すれば解決 public class Unbelievable { static Integer i; public static void main(String[] args) { if (i == 42) System.out.println("Unbelievable"); } }
  7. 7. 恐ろしく遅いプログラム <基本データ型のほうがボクシングされた基本データ型よりも時間・ 空間においてより効率的> public static void main(String[] args) { long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += Long.valueOf(1); // ここでオートボクシングが行わ れる! } System.out.println(sum); }
  8. 8. ボクシングされた基本データ型を 使用すべきとき  コレクション内の要素、キー、値として  より一般的には、パラメータ化された型の型パラ メータとして  ☓Collection<int>  ○ Collection<Integer>  リフレクションによってメソッドを呼び出す とき  参照: 項目53
  9. 9. まとめ  選択できる場合には、ボクシングされた基本デー タではなく、基本データ型を使用する  ボクシングされた基本データを使用する場合、注 意する  == では同一性比較が行われること  ボクシングされた基本データとアンボクシングされた 基本データとの計算では、アンボクシングが行われる こと  アンボクシングの際に、NullPointerException をスローす る可能性がある  基本データ値をボクシングする際、コストを要する不 必要なオブジェクト生成を行う可能性があること
  10. 10. 項目50 他の型が適切な場所では、文字列を避け る
  11. 11. 文字列は、他の値型に対する 代替としては貧弱  外部から入ってきたデータはたいてい文字列 だが、より適切な値に変換してから扱うべき  数値なら int、float、BigInteger 等  真偽値なら、boolean  等々  もし適切な型がなければ、適切な値型を書く べき
  12. 12. 文字列は、列挙型に対する 代替としては貧弱  enum の方がはるかに優れている  参照: 項目30
  13. 13. 文字列は、集合型に対する 代替としては貧弱 よりは、こうしよう String compoundKey = className + "#" + i.next(); private static class CompoundKey { private String className; private String methodName; ... }
  14. 14. 文字列は、capability に対する 代替としては貧弱  ところで、capability って?
  15. 15. capability って?(1) capability【名詞】 1【不可算名詞】 [具体的には 【可算名詞】] a〔…の〕能力,才能,手腕,〔…すること〕のできること[能力, 才能] 〔for,in,of〕. 用例: evaluate the capability of a person 人の才能を評価する. 2【不可算名詞】 a(物のもつ)〔…する〕特性,性能 〔for〕. 用例 the capability of gases for compression ガスの圧縮する性質. ...
  16. 16. capability って?(2)  Effective Java の例では、「偽造できない キー」のことを capability と呼んでいるようで す(pp.218)  「時折、文字列はある機能へのアクセスを与 えるために使用されます」(pp.217)  ThreadLocal の例でいうと、「スレッドロー カルな変数にアクセスするためのキー」なの で、(情報にアクセスする)「能力」の訳語 が割と近そうです  でも「能力」じゃやっぱり意味不明なので、 capability と呼びます
  17. 17. (capability の説明に用いられてい る)ThreadLocal って?  個々のスレッドが固有の値を持つための変数  現在の Java では、以下のようなかたちでライ ブラリとして提供されている public final class ThreadLocal<T> { public ThreadLocal(); public void set(T value); public T get(); }
  18. 18. capability として、 String の不適切な使用 public class ThreadLocal { private ThreadLocal() {} // インスタンス化不可能 // 名前付き変数に対するカレントスレッドの値を設定する。 public static void set(String key, Object value); // 名前付き変数に対するカレントスレッドの値を返す。 public static Object get(String key); }
  19. 19. 「capability として、 String の不適切な使用」の問題点  キーが共有されたグローバルな名前空間を表 している  クライアントが提供した文字列キーが一意でなけ ればならない  2 つの独立したクライアントが同じ名前を使って しまったら、意図せず変数を共有してしまう  意図して同じ名前を使うこともできてしまう(セ キュリティの問題)
  20. 20. 本物の capability public class ThreadLocal { private ThreadLocal() {} // インスタンス化不可能 public static class Key { // capability Key(); } // 一意の偽造できないキーを生成する public static Key getKey() { return new Key(); } public static void set(Key key, Object value); public static Object get(Key key); }
  21. 21. ThreadLocal に、もはや Key は不 要  set / get をインスタンスメソッドにする  ThreadLocal のインスタンス自体が capability public class ThreadLocal { public ThreadLocal(); public void set(Object value); public Object get(); }
  22. 22. ThreadLocal を型安全にする  これが(概ね)java.lang.ThreadlLocal が提供 している API public final class ThreadLocal<T> { public ThreadLocal(); public void set(T value); public T get(); }
  23. 23. まとめ  より良いデータ型が存在する、あるいは書く ことができる場合に、何も考えずに文字列で オブジェクトを表現したりしない  間違って文字列を使いがちなのは、基本デー タ型、enum、集合型(それから、capability)
  24. 24. 項目51 文字列結合のパフォーマンスに用心する
  25. 25. 文字列結合のパフォーマンス  文字列結合演算子(+)は、便利  だが、n 個の文字列結合は、O(n^2) となる  なぜなら、文字列は immutable だから
  26. 26. 文字列結合の不適切な使用 public String statement() { String result = ""; for (int i = 0; i < numItems(); i++) result += lineForItem(i); // String 結合 return result; }
  27. 27. String の代わりに StringBuilder を使用する public String statement() { StringBuilder b = new StringBuilder(numItems() * LINE_WIDTH); for (int i = 0; i < numItems(); i++) b.append(lineForItem(i)); return b.toString(); }
  28. 28. まとめ  パフォーマンスが重要でない場合以外には、 数個以上の文字列を結合するのに文字列結合 演算子を使用しない  代わりに、StringBuilder の append メソッド を使用する  あるいは、文字配列を使用するか、文字列を 結合する代わりに 1 つずつ処理する  あえてそうすべき時はほとんどなさそうですが ……。
  29. 29. 項目52 インタフェースでオブジェクトを参照す る
  30. 30. オブジェクトを参照するには、ク ラスよりもインタフェースを使用 すべき  適切なインタフェース型が存在するならば、 パラメータ、戻り値、変数、フィールドはす べてインタフェース型を使用して宣言される べき  オブジェクトのクラスを参照する必要がある 唯一の場合は、そのオブジェクトを生成する とき
  31. 31. List インタフェース / Vector クラスでの例 // 良い - 型としてインタフェースを使用 // subscribers は同期されている必要がある List<Subscriber> subscribers = new Vector<Subscriber>(); // 悪い - 型としてクラスを使用 Vector<Subscriber> subscribers = new Vector<Subscriber>();
  32. 32. 型としてインタフェースを 使用するメリット List<Subscriber> subscribers = new ArrayList<Subscriber>();
  33. 33. 型としてインタフェースを 使用する注意点  コードが、インタフェースの一般契約で要求され ていない(が、実装クラスは提供している)機能 に依存しているなら、実装クラスを変更すると き、新たな実装がその機能を提供しているかどう かが重要となる  例)「Vector が同期されている」ことに依存する コードを書いていれば、それを ArrayList に置き換え ることはできない  そのようなときは、変数を宣言する場所に、その要件 をドキュメント化すること!  インタフェースを用いることで型の表現力の一部を捨てて しまっているので、(それを補う)これは重要だと思いま す
  34. 34. インタフェースを使用する 利点にあずかった一例  java.lang.ThreadLocal  フィールドに Map を持つ  1.3 リリースでは、HashMap を用いていた  1.4 リリースでは、IdentityHashMap に変更する ことで、より速くなった
  35. 35. 適切なインタフェースが存在しない場 合は、クラスでオブジェクトを参照す る  String や BigInteger などの値クラス  より一般的には、具象クラスが関連付けされたイ ンタフェースを持たないとき  例)Random  クラスに基づくフレームワークに属する場合  例)java.util.TimerTask  インタフェースは実装しているが、そのイン タフェースにない特別なメソッドをクラスが 提供している場合  例)PriorityQueue
  36. 36. まとめ  ある与えられたオブジェクトが適切なインタ フェースを持っているかどうかを調べる  インタフェースを持っていれば、オブジェク トを参照するためにインタフェースを使用し て、プログラムをより柔軟にする  インタフェースを持っていなければ、クラス 階層中で必要な機能を提供している最も上位 のクラスを使用する

×