はじめに
読書会に参加していないところがあるので、そこは議事録を読みながら、なるべく自分の言葉で書いていきます!
読んだところ
175 ページ〜 222 ページ
引数の検査をきちんとして javadoc の @throws に書く
- IllegalArgumentException
- IndexOutOfBoundsException
- NullPointerException
などは、事前に引数チェックして出す。たとえば、 OpenJDK の String(byte[], int, int, String) では、以下のような実装になっている、自分で引数チェックをして、その内容を明確に @throws に記述している。
// チェック関数 private static void checkBounds(byte[] bytes, int offset, int length) { if (length < 0) throw new StringIndexOutOfBoundsException(length); if (offset < 0) throw new StringIndexOutOfBoundsException(offset); if (offset > bytes.length - length) throw new StringIndexOutOfBoundsException(offset + length); } /** * (snip) * * (以下のように javadoc に書く) * * @throws IndexOutOfBoundsException * If the {@code offset} and {@code length} arguments index * characters outside the bounds of the {@code bytes} array * * @since JDK1.1 */ public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException("charsetName"); checkBounds(bytes, offset, length); // ここで引数チェック // (snip) }
受け取ったらすぐにチェック!
以下の場合は引数チェックしない
- コストがデカい
- 引数のチェックが、自体が元々やりたい処理の一部の場合は 2 回チェックすることになるので、やらなくていい
防御的コピー
不変オブジェクトが理想的だけど、可変オブジェクトを自分以外から破壊されないようにコピーしてしまうことも重要。
これも簡単な話で、OpenJDK の java.lang.String の実装では、以下のように char 配列を防御的にコピーしている。他のオブジェクトからの変更可能性を排除して、自分は不変オブジェクトでいられる!
public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.offset = 0; this.count = count; // 防御的コピー!!!! this.value = Arrays.copyOfRange(value, offset, offset+count); }
メソッド名
Java の標準ライブラリのメソッド名などを参考に、いい名前にしましょう
便利なメソッドは要望が出てから
最初から、便利なメソッドを作り過ぎない><
シンプルなものだけ提供して、使われる箇所を一通り見てから追加したければする。
引数多すぎ自重
4 つまで。
引数の減らし方
可変長引数
引数がひとつ必須の場合は
static int sub(int ... args) { /* ... */ }
じゃなくて
static int sub(int first, int ... args) { /* ... */ }
配列を表示する
System.out.println(Arrays.toString(array)); // これが正解 System.out.println(Arrays.asList(array)); // こうじゃないよ、これは可変長引数だからね
可変長引数はあまり乱用しない
不適切に使用すると、困惑させちゃうから
static void foo(Object ... args) とかはダメよ☆
配列やコレクションを返すメソッドで null を返すな
空配列や空コレクションを返すように!
ちなみに空配列は不変オブジェクトなので、使いまわせるので軽い。
javadoc
書け
変数スコープはちっちゃくね
- 変数宣言は変数が使われるところで書く
- 宣言時初期化
- while より for、 for より for-each
- Iterable を実装すれば、なんでも for-each!
- メソッドもちっちゃくね
とにかく変数の使われるところをはっきりさせる
ライブラリを使え
ライブラリを使え
車輪の再発明するなー!!
float, double は 0.1 を正確に表現できない
BigDecimal 使えと
丸め方まで制御可能
ボクシングされたデータ型に == はダメ
あたりまえだけど、よくある間違い
文字列結合して意味を持たせるのはダメ
面倒でもクラス作る
文字列結合
StringBuilder 使いましょう StringBuffer は無駄に synchronized なので遅い
あるならインタフェース使う
以下より
ArrayList<Foo> = new ArrayList<Foo>();
以下のほうがいい。
List<Foo> = new ArrayList<Foo>();
あとから修正が楽
まとめ
今回は、多めですが内容が簡単な章でした!