IT戦記 このページをアンテナに追加 RSSフィード Twitter

2010-02-25

Effective Java 読書会 8 日目 「それ enum で出来るよ」

はじめに

ビット演算? それE... - はてなちゃんセリフ - はてなセリフ

今日読んだところ

143 ページ〜 159 ページ

前回はこちら

Effective Java 読書会 7 日目 「PECS! PECS! PECS!」 - IT戦記

int 定数とか使わない

型安全じゃないから

enum 使う

enum Hoge {
    FOO, BAR;
}

簡単

メソッドも持てる

enum Hoge {
    FOO, BAR;

    void a() {
        /* (snip) */
    }
}

で、以下のように使う

Hoge.FOO.a();

シングルトンも

最近の Java では enum でやるらしい!

switch 文の代わりに固有メソッド 

enum Hoge {
    FOO { void a() { /*snip*/ } },
    BAR { void a() { /*snip*/ } };

    abstract void a();
}

以下のコードが

// これはダメ
switch(obj) {
    case Hoge.FOO: /*snip*/ break;
    case Hoge.BAR: /*snip*/ break;
    default: throw new AssertionError();
}

以下で良くなる!

// case の書き忘れもなくて安心!
obj.a();

戦略 enum

enum の値をカテゴライズする

// たとえば
enum Hoge {
    FOO { void a() { /*snip*/ } }, // これと
    BAR { void a() { /*snip*/ } }, // これがまったく同じ処理だったとして
    BAZ { void a() { /*snip*/ } };

    abstract void a();
}

以下のようになる

enum Hoge {
    FOO(Strategy.STRATEGY_1),
    BAR(Strategy.STRATEGY_1),
    BAZ(Strategy.STRATEGY_2);

    private enum Strategy {
        STRATEGY_1 { void a() { /* ... */ } }, STRATEGY_2 { void a() /* ... */ }

        abstract void a();
    }

    // 戦略の委譲
    private final Strategy strategy;
    Hoge(Strategy strategy) { this.strategy = strategy; }
    void a() { strategy.a(); }
}

values 便利

for (Hoge v : Hoge.values()) { /* ... */ }

インスタンス配列

ordinary は使うのはやめましょう

値が増えるとコンパイルの度に順番変わるので

private で id 的なフィールドを持てと

EnumSet 便利!

64 個までならビット演算(|)と比べても遜色のない速度で動く!テラすごす!!

Set<Hoge> set = EnumSet.of(Hoge.FOO, Hoge.BAR, Hoge.BAZ);  // ビット演算 FOO (=0x1) | BAR (=0x1 << 1) | BAZ (=0x1 << 2) と比べても遜色のない速度で動く

of メソッドかっけー!

EnumMap も便利

Enum の ordinal をインデックスにした配列じゃなく EnumMap を使おう

まとめ

enum すげー便利!めっちゃ使う!

次回はこちら

Effective Java 読書会 9 日目 「Enum の拡張とアノテーション」 - IT戦記

Effective Java 読書会 7 日目 「PECS! PECS! PECS!」

はじめに

一番PECSにこだわってる... - ズバリどうぞ - はてなセリフ

今日読んだところ

126 ページ〜 142 ページ

前回はこちら

Effective Java 読書会 6 日目 「ジェネリクス!」 - IT戦記

Object を使ったその瞬間が

ジェネリック型を使うチャンスなのです!!!

たとえば、以下みたいな

public class Stack {

    /* snip */

    public Object pop() {
        /* snip */
    }

    public void push(Object e) {
        /* snip */
    }
}

こうなる

public class Stack<E> {

    /* snip */

    public E pop() {
        /* snip */
    }

    public void push(E e) {
        /* snip */
    }
}

Object を使わなくすると

キャストがなくなる

キャスト良くない!例外でるからね!

どうしてもキャストしなきゃだめなパターン

配列をラップするためのジェネリックス型を使う場合は、キャストしなきゃしょうがない

public class Stack<E> {

    private E[] elements;

    Stack() {
        elements = new E[100]; // 出来ません><
    }

    public E pop() {
        /* snip */
    }

    public void push(E e) {
        /* snip */
    }
}

なので、

public class Stack<E> {

    private E[] elements;

    Stack() {
        elements = (E[]) new Object[100]; // とか
    }

    public E pop() {
        /* snip */
    }

    public void push(E e) {
        /* snip */
    }
}
public class Stack<E> {

    private Object[] elements;

    Stack() {
        elements = new Object[100];
    }

    public E pop() {
        element = (E) elements[index]; // みたいな
        /* snip */
    }

    public void push(E e) {
        /* snip */
    }
}

論理的に安全なことを確認して、 @SuppressWarnig("uncheck") しちゃいな YO!

ジェネリックメソッドもアルよねー

アルよねー

コンストラクタ型推論するために static なジェネリックメソッドつかうよねー

よねー

コンストラクタ型推論

Java 7 では HashMap<String, String> map = new HashMap<>(); みたいになるらしい YO! という話がでた

PECS! PECS!

プロデューサは extends 、コンシューマは super だってばよ!

たとえば、

public Hoge {

    // producer は CharSequence のプロデューサ
    // consumer は CharSequence のコンシューマ
    public static void foo(List<? extends CharSequence> producer, List<? super CharSequence> consumer) {

        // プロデューサからは get できる
        CharSequence hoge = producer.get(0);

        // コンシューマには set できる
        consumer.set(0, hoge);

        // 以下はコンパイルエラー
        producer.set(0, hoge);
        hoge = consumer.get(0);
    }
}

ジェネリックな型を作ったら

境界ワイルドカードを意識せずにその型を使えるか確認する

super extends も問題なく使えるか確認。

型トークン

Class を渡すことを型トークンというよ!静的動的に型安全!

まとめ

魔法の弾丸 PECS!

次回はこちら

Effective Java 読書会 8 日目 「それ enum で出来るよ」 - IT戦記