The King's Museum

ソフトウェアエンジニアのブログ。

【Effective Java】項目31:序数の代わりにインスタンスフィールドを利用する

ordinal() メソッド

enum は ordinal() というメソッドを持っています。 これは列挙宣言での位置を返すメソッドです。

public enum Week {
    Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday;
}

Week.Sunday.ordinal();    // => 0
Week.Monday.ordinal();    // => 1
Week.Tuesday.ordinal();   // => 2
Week.Wednesday.ordinal(); // => 3
Week.Thursday.ordinal();  // => 4
Week.Friday.ordinal();    // => 5
Week.Saturday.ordinal();  // => 6

ordinal() で取得できる数を定数にひもづくデータとして使ってはいけません。

public enum Ensemble {
    SOLO, DUET, TRIO, QUARTET, QUINTET,
    SEXTET, SEPTET, OCTET, NONET, DECTET;

    // グループのメンバーの数を返す
    public int numberOfMusicians() { return ordinal() + 1; }
}

上記の enum では、アンサンブルのメンバーの人数を ordinal() を使って実装しています。 この状態では上手く動きますが、今後の発展を考えると以下のような問題が生じます。

  • 定数を並び替えるとメソッドが動作しなくなる
  • 同じ数字を持つ定数(たとえば 8 人のミュージシャンがいるダブルカルテット)は割り当てられない

もともと、ordinal() は EnumSet や EnumMap など、enum に対するデータ構造を実装する手助けとして提供されています。 そのため、普通の開発者が ordinal() を使うことはほぼありません。

インスタンスフィールドを使う

ordinal() を使うのではなく、項目30で説明したインスタンスフィールドを使うべきです。

public enum Ensemble {
    SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
    SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
    NONET(9), DECTET(10), TRIPLE_QUARTET(12);

    private final int size;
    Ensemble(int size) { this.size = size; }
    public int numberOfMusicians() { return this.size; }
}

こうすることで、上述した問題はすべて解決されています。

感想

今回はたった1ページの項目だったのでまとめるのが楽だった。

(c) The King's Museum