Effective Java 読書会 第1回目のまとめだよ。
しかだよ。Effective Javaの読書会を始めたのでブログにまとめてみるよ。
輪講
福岡の30歳前後プログラマー @daichan4649 @seisuke @kensei_kick @kenz_firespeed @shikajiro で始めました。早速 @daichan4649 が仕事で来れなかったので、次回、抹茶オレをおごってもらうことにします。 :)
というわけで議事録みたいなまとめ。
第1章 はじめに
前説なので飛ばします。
第2章 オブジェクトの生成と消滅
new Hoge(); について考える章ですね。newとかstaticファクトリーメソッドとかfinalizeとかについて書いてます。
項目1 コンストラクタの代わりにstaticファクトリーメソッドを検討する。
いきなりnew使うなって説明です。staticファクトリーメソッドを使う良さが解説されてます。以下メリット。
1.名前を持つのでオブジェクト生成が分かりやすくなる。
- new HogeClass(1,2,3);
- HogeClass.createTriangle(1,2,3);
2.オブジェクトを生成しなくても良いので、パフォーマンスを調整できる。
例えばこんなの風に書けば、instanceは2個以上生成されないのでパフォーマンスが向上する。
private HogeClass instance; public HogeClass createTriangle(int a, int b, int c){ if(instance != null){ return instance; }else{ instance = new HogeClass(a, b, c); return instance; } } //もちろん適当に書いたサンプルコードだから、このソースコードに有用性があるとかないとかについて突っ込んじゃだめだぜっ。
3.返すクラスを隠蔽化できる。
自分自身のクラスを生成するだけではなく、自分のサプクラスのインスタンスも返せます。
- extendsの実装をnon publicにして隠蔽化できる。
- インターフェースさえ同じであれば、どんな実装でもOK。
- 返すClassは実装してなくてもいい。
ここらへんはインターフェースを活かした実装の話ですね。
4.めんどいパラメータを省略できる。
ジェネリクスを省略できます。
List<String> list = new ArrayList<String>();
List<String> list = HogeList.createInstance();
短所
1.サブクラスは作れなくなる。
privateコンストラクタのクラスは継承できない。でも、継承ではなく委譲を促すのでよしとする。
2.普通のstaticメソッドと見分けがつかない。
そんな時は命名規則に従おう。
valueOf | 型変換 |
of | valueOfの省略形 |
getInstance | シングルトンインスタンスを返す |
newInstance | 毎回別のインスタンスを返す。限りなくnewと同じ。 |
getType | 自分とは別のクラスのシングルトンインスタンスを返す。 |
newType | 自分とは別のクラスのインスタンスを返す。 |
※鹿訳なので、正確な意味はEffective Java 第2版を買ってね!
この命名規則は役に立つ!ルールに従うのがユーザーも実装者も困らない。
項目2 数多くのコンストラクタパラメータに直面したときにはビルダーを検討する
パラメーターが多いときはbuilderパターンで。
1.テレスコーピングパターン
2.setterでがんばる。
- 不整合が起きやすい。
3.そんなあなたにビルダーパターン
- 1.と2.のイイトコどり。
- 整合性チェックを実行出来る。
- 防御的コピーとかちゃんとしようね。
AndroidだとAlertDialog.Builderがよく使われますね。
欠点
1.パフォーマンスが落ちる
- でもちょっと重くなるくらいなので、そんなに気にしない。
2.ソースコードが冗長になる。
- 4個以上になりそうならbuilderで
項目3 privateのコンストラクタかenum型でシングルトン特性を強制する。
3つのやり方。
1.publicなフィールドにstatic finalで持つ。
public static final Hoge INSTANCE = new Hoge();
2.privateなフィールドのインスタンスをメソッド経由で取得する。
private static final Hoge INSTANCE = new Hoge(); public Hoge getInstance(){ return INSTANCE; }
3.enumでやる。
なんだってー!
public enum Hoge{ INSTANCE; public void hoge(){} } //使うとき Hoge.INSTANCE.hoge();
シリアライズの問題も解決しており、これが現時点で最善の実装のようです。
項目4 privateのコンストラクタでインスタンス化不可能を強制する
ここまで読んでる時点で、privateのコンストラクタが登場しまくってますがいいでしょう。
ユーティリティクラスとかでインスタンス化させたくないときに有効なやり方。
項目5 不必要なオブジェクト生成を避ける
パフォーマンス改善のお話。
- staticファクトリーメソッドで不要なインスタンス生成を防ぐ
- 不変オブジェクトと変更されない可変オブジェクトの再利用
- 遅延初期化はそんなにパフォーマンス良いわけじゃないし、可読性も下がるので、無理してしないほうがいい。
- 自動アンボクシングに注意
- とはいえ、防御的コピーはきちんとしよう。
まとめとして、不必要なオブジェクト生成は避けたほうがいいけど、あくまでパフォーマンス改善の恩恵があるだけなので、必要な場所で防御的コピーをしてバグやセキュリティホールが出ないようにすることの方が大事。たしかに。
項目6 廃れたオブジェクト参照を取り除く
- 配列とかの独自のメモリ管理をするときはメモリリークに注意しよう。
- キャッシュはWeakHashMapで表現するといいよ!
- リスナーやコールバックにも注意すること。
項目7 ファイナライザを避ける
使っちゃダメ。以上。
ダメな理由
- 即座に呼ばれない。
- 実行保証すらない。
- なぜかパフォーマンスが落ちる。
- try finnalyで書け!
そんなファイナライザにもメリットが!!
1. finnaly忘れのセーフティネット。dbのclose忘れでdbがロックされっぱなしになるより、実行保証ないけど、いつかcloseされる方がマシとかかな。警告ログを出力して、プログラマにcloseを喚起すること。
2. ネイティブオブジェクトの開放
ネイティブオブジェクト(Cとかの資源かな?)はガーベッジコレクションでメモリクリアされないので、手動でやる必要がある。などなど、ファイナライザはいろいろ大変なのでEffective Java 第2版を買って読もう!
第3章も途中までやったのですが、疲れたので次回一緒にまとめます。