More Related Content
Similar to Effective Java 輪読会 項目45-48
Similar to Effective Java 輪読会 項目45-48 (20)
More from Appresso Engineering Team
More from Appresso Engineering Team (13)
Effective Java 輪読会 項目45-48
- 2. 第8章 プログラミング一般
項目45 ローカル変数のスコープを最小限にする
項目46 従来の for ループより for-each ループを選ぶ
項目47 ライブラリーを知り、ライブラリーを使う
項目48 正確な答えが必要ならば、float と double を避ける
項目49 ボクシングされた基本データより基本データ型を選ぶ
項目50 他の型が適切な場所では、文字列を避ける
項目51 文字列結合のパフォーマンスに用心する
項目52 インタフェースでオブジェクトを参照する
項目53 リフレクションよりインタフェースを選ぶ
項目54 ネイティブメソッドを注意して使用する
項目55 注意して最適化する
項目56 一般的に受け入れられている命名規約を守る
2
- 5. ローカル変数は初めて使うときに宣言
5
ローカル変数を早めに宣言する場合
処理を理解しようとする読み手の注意を逸らしてしまう
たくさんの変数を(一時的に)覚えることで、大事な部分への注意が散らして
しまう
変数使用された時に型と初期値を思え出せないかも
// ブロックの先頭に宣言するのは C 言語のスタイル、やらないこと
void declarationInCStyle() {
int i = 0, j = 0, k = 0; // ループ制御用
String s1, s2, ... // 文字列変数いろいろ
double d1, d2, ... // 数値変数いろいろ
... // 変数宣言たくさん...覚えきれんわ!
{
...
x = y; // えっと、こいつらの初期値と型は...何だっけ?
}
}
- 6. ローカル変数宣言と初期化子
6
ほとんどローカル変数宣言は初期化子を含んでいるべき
初期化子を含むことで初期化漏れ防止
変数を合理的に初期化する情報を揃えてから変数を宣言(&初期化)
初期化に必要な情報が足りない場合、宣言を先送りすべき
void declarationWithoutInit() {
int var; // まだ使わないけど先に宣言しておこう
... // いろいろ書いたら数ページになって(そこまで書いたらメソッドを分けたほうがいいけ
ど)
var++; // えっと、初期化した...よね?
...
}
void declarationWithInitInfo() {
Variable tooEarly; // 初期化の情報が足りていない ⇒ 早すぎる
... // いろいろ情報収集
Info info = collectInfo(args); // ここに来てやっと情報が揃った
Variable properTime = new Variable(info); // 使用直前に宣言&初期化 ⇒ 適切なタイミング
useVariable(properTime);
...
}
- 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
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
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());
}
- 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
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. Iterable インタフェース
15
Iterable インタフェースを実装することで for-each 使用可能に
要素のグループを実装する際、 Collection を実装しなくても、
Iterable を実装するように
public interface Iterable<E> {
Iterator<E> iterator();
}
- 16. まとめ
16
明瞭性とバグ予防に関して、 for-each ループは for ループより
優れた長所提供し、パフォーマンス上のペナルティはない
for-each ループを使用できない3つの状況
フィルタリング:コレクションをイテレートして選択された要素だけ削除
する
⇒ イテレータ使用して remove メソッドを呼び出す
変換:リストや配列をイテレートして一部か全部の要素の値を置換する
⇒ リストイテレータか配列インデックス変数が必要
並列イテレーション:複数のコレクションを並列にイテレートする
⇒ イテレータやインデックス変数に対して明示的な制御が必要
- 18. 標準ライブラリーを使おう
18
整数の乱数を生成メソッド例の教訓
本当にいい random メソッドは、いろいろ知らないと作れないので、
標準ライブラリーではすでにやってくれたから、それを使いましょ
う!
標準ライブラリーを利用する利点
専門家の知識と、以前それを利用した人々の経験を利用することになる
時間を無駄にする必要がなく、目的の課題に集中できる
自分では何もしなくても、時間と共にパフォーマンスが改善されたりす
る
自分のコードを主流に置くことになる
- 22. float 型と double 型は近似計算
22
科学計算と工学計算のために設計されている
2進数浮動小数点算数
広い範囲の大きさに対して正確な近似を行う
正確な結果を提供しない
⇒ float 型と double 型は、特に金銭計算に適しない
- 24. まとめ
24
正確な答えを必要とする計算は float や double を使用しない
代わりに BigDecimal か、 int や long を使用する
BigDecimal を使用する状況
システムに小数点を把握させたい
基本データ型を使用しない不便さとコストを気にしない
丸めを完全に制御したい
数が大きい(18桁を超える)
int や long を使用する状況
パフォーマンスが重要
小数点の把握が気にならない
数が大きすぎない(9桁を超えないならint、18桁を超えないならlong)