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 輪読会 項目45-48

1,069 views

Published on

Published in: Technology
  • Login to see the comments

  • Be the first to like this

Effective Java 輪読会 項目45-48

  1. 1. Effective Java 輪読会 Item 45-48 開発部 陳映融 2014/2/19
  2. 2. 第8章 プログラミング一般  項目45 ローカル変数のスコープを最小限にする  項目46 従来の for ループより for-each ループを選ぶ  項目47 ライブラリーを知り、ライブラリーを使う  項目48 正確な答えが必要ならば、float と double を避ける  項目49 ボクシングされた基本データより基本データ型を選ぶ  項目50 他の型が適切な場所では、文字列を避ける  項目51 文字列結合のパフォーマンスに用心する  項目52 インタフェースでオブジェクトを参照する  項目53 リフレクションよりインタフェースを選ぶ  項目54 ネイティブメソッドを注意して使用する  項目55 注意して最適化する  項目56 一般的に受け入れられている命名規約を守る 2
  3. 3. Item 45 ローカル変数のスコープを最小限にする
  4. 4. ローカル変数のスコープ 4  復習:ローカル変数のスコープは宣言のあと、ブロックが終わるま で  ローカル変数のスコープを最小化することで、コードの可読性と保 守性が向上し、誤りの可能性が減る  本質的には項目13 「クラスとメンバーへのアクセスを最小限にする」 と類似 void scopeSample() { ... // 未宣言 int var = 0; // ここからが var のスコープ { ... var--; // 内部ブロックもスコープに含まれる } var--; // 所在ブロックが終わるまで有効 }
  5. 5. ローカル変数は初めて使うときに宣言 5  ローカル変数を早めに宣言する場合  処理を理解しようとする読み手の注意を逸らしてしまう  たくさんの変数を(一時的に)覚えることで、大事な部分への注意が散らして しまう  変数使用された時に型と初期値を思え出せないかも // ブロックの先頭に宣言するのは C 言語のスタイル、やらないこと void declarationInCStyle() { int i = 0, j = 0, k = 0; // ループ制御用 String s1, s2, ... // 文字列変数いろいろ double d1, d2, ... // 数値変数いろいろ ... // 変数宣言たくさん...覚えきれんわ! { ... x = y; // えっと、こいつらの初期値と型は...何だっけ? } }
  6. 6. ローカル変数宣言と初期化子 6  ほとんどローカル変数宣言は初期化子を含んでいるべき  初期化子を含むことで初期化漏れ防止  変数を合理的に初期化する情報を揃えてから変数を宣言(&初期化)  初期化に必要な情報が足りない場合、宣言を先送りすべき void declarationWithoutInit() { int var; // まだ使わないけど先に宣言しておこう ... // いろいろ書いたら数ページになって(そこまで書いたらメソッドを分けたほうがいいけ ど) var++; // えっと、初期化した...よね? ... } void declarationWithInitInfo() { Variable tooEarly; // 初期化の情報が足りていない ⇒ 早すぎる ... // いろいろ情報収集 Info info = collectInfo(args); // ここに来てやっと情報が揃った Variable properTime = new Variable(info); // 使用直前に宣言&初期化 ⇒ 適切なタイミング useVariable(properTime); ... }
  7. 7. ローカル変数宣言と初期化子 7  前述規則(ローカル変数宣言は初期化子を含んでいるべき)の例外: try-catch 文  チェックされる例外を投げるメソッドの戻り値で変数を初期化する場合  Java 1.7 の AutoCloseable の導入で Closeable も規則適用可能に  try-with-resources: static void tryCatchSample() { BufferedReader br = null; try { br = new BufferedReader(new FileReader(“filePath”)); // 初期化で例外を投げるかも System.out.println(br.readLine()); // ここにも例外を投げる可能性がある } catch (IOException ex) { ... } finally { if (br != null) br.close(); // try ブロックの外での使用、宣言はブロック外でなければ } } static void tryWithResourcesSample() throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(“filePath”))) { // br のスコープは try ブロック内 System.out.println(br.readLine()); } }
  8. 8. ループでの変数スコープ最小化 8  for と for-each はループ変数を宣言できる  変数スコープはループ本体と for 予約語の後の括弧内のコードに限定  ループごとの冗長な計算を同じ結果が返される場合、ループ変数で回避 // コレクションをイテレートする好ましいイデオム for (Element e : c) { doSomething(e); } // リリース 1.5 より前のジェネリックがない場合、いまも使えるけど... for (Iterator i = c.iterator(); i.hasNext(); ) { doSomething((Element) i.next()); } // 初期化時に一回だけ処理 for (int i = 0, n = expensiveComputation(); i < n; i++) { doSomething(i); }
  9. 9. ループでの変数スコープ最小化 9  while の場合、だいたいブロックの外で宣言される変数を使用する  コピー&ペーストや要素変数名の再利用でバグを織り込みやすい  for ループ使用する場合はコンパイル時エラーで検出可能 Iterator<Element> i = c1.iterator(); while (i.hasNext()) { doSomething((Element) i.next()); } // バグがあるけど問題なくコンパイルできる Iterator<Element> i2 = c2.iterator(); while (i.hasNext()) { doSomething((Element) i.next()); } // NoSuchElementException! for (Iterator<Element> i = c1.iterator(); i.hasNext(); ) { doSomething((Element) i.next()); } // コンパイル時エラー - シンボル i は解決できない for (Iterator<Element> i2 = c2.iterator(); i.hasNext(); ) { doSomething((Element) i2.next()); }
  10. 10. メソッドを小さくする 10  メソッドを小さくして、処理をはっきりさせる  一つのメソッドに複数の処理があって、 一つの処理用のローカル変数が別の処理のコードのスコープ内にある場 合 ⇒ メソッドを分ける(一つの処理に対して一つのメソッド)
  11. 11. まとめ 11  ローカル変数のスコープを最小化することで  コード可読性と保守性が向上  誤りの可能性が減る  ローカル変数のスコープを最小限にする技法  ローカル変数が初めて使用される時に宣言する  ローカル変数は初期化子を含んで宣言する  ループの場合、 while ループより for ループを選ぶ  ループ終了後にループ変数の内容が必要ない場合に限る  メソッドを小さくして焦点をはっきりさせる
  12. 12. Item 46 従来の for ループより for-each ループを選ぶ
  13. 13. イテレーション用の変数隠蔽 13  リリース 1.5 より前のイテレーション  コレクション、ジェネリックがない場合  配列の場合  イテレータやインデックス変数を隠蔽してエラーの機会を排除  配列上限計算は一度だけなので、パフォーマンス上のペナルティはない // イテレータ変数を宣言以外の部分で間違えてると、コンパイル時に検出できないかも for (Iterator i = c.iterator(); i.hasNext(); ) { doSomething((Element) i.next()); } // インデックス変数を宣言以外の部分で間違えてると、コンパイル時に検出できないかも for (int i = 0; i < a.length; i++) { doSomething(a[i]); } // コレクションと配列をイテレートする好ましいイデオム for (Element e : c) { doSomething(e); }
  14. 14. ネストしたイテレーション 14  for ループでのイテレータ変数の操作で使用ミス例  next メソッドの過剰な呼び出し ⇒ 外側要素を変数で保持するように修正...  for-each ループで実装したほうが簡潔 for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); ) decks.add (new Card(i.next(), j.next()); // i が底をついたら NoSuchElementException // コレクションと配列をイテレートする望ましいイデオム for (Suit suit : suits) for (Rank rank : ranks) decks.add (new Card(suit, rank)); for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) { Suit suit = i.next(); for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); ) decks.add (new Card(suit, j.next()); }
  15. 15. Iterable インタフェース 15  Iterable インタフェースを実装することで for-each 使用可能に  要素のグループを実装する際、 Collection を実装しなくても、 Iterable を実装するように public interface Iterable<E> { Iterator<E> iterator(); }
  16. 16. まとめ 16  明瞭性とバグ予防に関して、 for-each ループは for ループより 優れた長所提供し、パフォーマンス上のペナルティはない  for-each ループを使用できない3つの状況  フィルタリング:コレクションをイテレートして選択された要素だけ削除 する ⇒ イテレータ使用して remove メソッドを呼び出す  変換:リストや配列をイテレートして一部か全部の要素の値を置換する ⇒ リストイテレータか配列インデックス変数が必要  並列イテレーション:複数のコレクションを並列にイテレートする ⇒ イテレータやインデックス変数に対して明示的な制御が必要
  17. 17. Item 47 ライブラリーを知り、ライブラリーを使う
  18. 18. 標準ライブラリーを使おう 18  整数の乱数を生成メソッド例の教訓  本当にいい random メソッドは、いろいろ知らないと作れないので、 標準ライブラリーではすでにやってくれたから、それを使いましょ う!  標準ライブラリーを利用する利点  専門家の知識と、以前それを利用した人々の経験を利用することになる  時間を無駄にする必要がなく、目的の課題に集中できる  自分では何もしなくても、時間と共にパフォーマンスが改善されたりす る  自分のコードを主流に置くことになる
  19. 19. 標準ライブラリーの知るべき機能 19  主要リリースごとに機能が追加されて、それを知ることは得るもの がある  標準ライブラリーの知るべき機能  java.lang  java.util (リリース 1.2 にコレクションフレームワーク追加)  java.util.concurrent (リリース 1.5 にコンカレンシーユティリティ追 加)  java.io (ある程度)  ちなみに、リリース 1.7 で追加された機能(の一部)  文字列による switch  ダイアモンド演算子  例外の機能拡張(リソース付き、安全な再スロー、マルチキャッチ)
  20. 20. まとめ 20  無駄な努力をしないこと  かなり共通だと思えることをする前に、まず標準ライブラリーから 使えるものを探す  一般的には、ライブラリーのコードは自分で書いたものより優れて いて、時間とともに改善されていく可能性がある
  21. 21. Item 48 正確な答えが必要ならば、float と double を避ける
  22. 22. float 型と double 型は近似計算 22  科学計算と工学計算のために設計されている  2進数浮動小数点算数  広い範囲の大きさに対して正確な近似を行う  正確な結果を提供しない ⇒ float 型と double 型は、特に金銭計算に適しない
  23. 23. 正確な答えを得るには 23  金銭計算など、正確な答えが必要な場合は、 BigDecimal か int か long を使用する  BigDecimal 型を使用  正確な値は出してくれるけど  基本データの算数型を使用するより不便(演算子は使えない)  遅い  int/long 型を使用  金額に応じて使い分ける  小数点がどこかを自分で把握しておく
  24. 24. まとめ 24  正確な答えを必要とする計算は float や double を使用しない  代わりに BigDecimal か、 int や long を使用する  BigDecimal を使用する状況  システムに小数点を把握させたい  基本データ型を使用しない不便さとコストを気にしない  丸めを完全に制御したい  数が大きい(18桁を超える)  int や long を使用する状況  パフォーマンスが重要  小数点の把握が気にならない  数が大きすぎない(9桁を超えないならint、18桁を超えないならlong)

×