web-dev-qa-db-ja.com

列挙型の序数を使用するのは良い習慣ですか?

私は列挙型を持っています:

_public enum Persons {

    CHILD,
    PARENT,
    GRANDPARENT;

}
_

ordinal()メソッドを使用して列挙型メンバー間の「階層」をチェックすることに問題はありますか?つまり、冗長性を除いてそれを使用する場合、将来誰かが誤って順序を変更する可能性がある場合、欠点はありますか?.

または、そのようなことをする方が良いですか:

_public enum Persons {

    CHILD(0),
    PARENT(1),
    GRANDPARENT(2);

    private Integer hierarchy;

    private Persons(final Integer hierarchy) {
        this.hierarchy = hierarchy;
    }

    public Integer getHierarchy() {
        return hierarchy;
    }

}
_
25
ByeBye

Enum.Javaordinalメソッドについてjavadocを参照する場合:

ほとんどのプログラマは、このメソッドを使用しません。 Java.util.EnumSetJava.util.EnumMapなど、洗練された列挙ベースのデータ構造で使用するために設計されています。

まず、マニュアル(この場合はjavadoc)を読んでください。

第二に、もろいコードを書かないでください。列挙値は将来変更される可能性があり、2番目のコード例はさらに多くのclearおよびmaintainableです。

新しい列挙値が(たとえば)PARENTGRANDPARENTの間に挿入される場合、将来の問題を作成することは絶対に望まないでしょう。

41
vikingsteve

最初の方法は、列挙型の順序が重要であることを理解するために列挙型が使用されているコードを読む必要があるため、直接理解できません
非常にエラーが発生しやすいです。

public enum Persons {

    CHILD,
    PARENT,
    GRANDPARENT;

}

2番目の方法はそのままの方が良い自己説明的

CHILD(0),
PARENT(1),
GRANDPARENT(2);

private SourceType(final Integer hierarchy) {
    this.hierarchy = hierarchy;
}

もちろん、列挙値の順序は、列挙コンストラクター引数によって提供される階層的な順序と一致している必要があります。

列挙値と列挙コンストラクタの引数の両方がそれらの階層を伝えるため、一種の冗長性を導入します。
しかし、なぜそれが問題になるのでしょうか?
列挙型は、定数であり、頻繁に変化しない値を表すように設計されています
OP列挙型の使用法は、適切な列挙型の使用法をよく示しています。

CHILD, PARENT, GRANDPARENT

列挙型は、頻繁に移動する値を表すようには設計されていません。
この場合、enumを使用することは、それを使用するクライアントコードを頻繁に破損する可能性があり、enum値が変更されるたびにアプリケーションの再コンパイル、再パッケージ化、および再デプロイを強制するため、おそらく最適な選択ではありません。

10
davidxxx

Effective JavaでJoshua Blochが示唆したように、enum値の順序を変更するとエンコードしたロジックが壊れる可能性があるため、enumに関連付けられた値をその序数から導出することはお勧めできません。

あなたが言及する2番目のアプローチは、著者が提案するものに正確に従います。それは、別のフィールドに値を保存することです。

列挙値の順序と階層の概念を切り離すので、あなたが提案した代替案は、拡張性と保守性が高いため、間違いなく優れていると思います。

7
msf1013

最初に、おそらく数値の順序値さえ必要ありません-それが Comparable の目的であり、Enum<E>Comparable<E>を実装します。

何らかの理由で数値の順序値が必要な場合do、はい、ordinal()を使用する必要があります。それが目的です。

Java Enumsの標準的な方法は、宣言順序でソートすることです。これがEnum<E>Comparable<E>を実装し、Enum.compareTo()finalである理由です。

Comparableを使用せず、宣言の順序に依存しない独自の非標準の比較コードを追加すると、コードを使用しようとする他の人(自分自身の将来の自己を含む)を混乱させるだけです。そのコードが存在することを誰も期待していません。彼らはEnumEnumであることを期待しています。

カスタムの順序が宣言の順序と一致しない場合、宣言を見る人は混乱するでしょう。 does(現時点では)が宣言順序と一致する場合、それを見る人はそれを期待するようになり、彼らは将来のある日にそれが起こらないとき、厄介なショックを受けるでしょう。 (カスタムオーダーが宣言オーダーと一致することをensureにコード(またはテスト)を記述した場合、それがいかに不要であるかを補強するだけです。)

独自の注文値を追加すると、自分でメンテナンスの頭痛の種になります。

  1. hierarchyの値が一意であることを確認する必要があります
  2. 中央に値を追加する場合、後続のすべての値の番号を変更する必要があります

将来、誰かが誤って順序を変更するのではないかと心配している場合は、順序を確認する単体テストを作成してください。

要するに、 Item 47の不滅の言葉では、ライブラリを知って使用します


追伸また、Integerを意味する場合は、intを使用しないでください。 ????

6
David Moles

ordinal()の使用は、enumの宣言の変更が順序値に影響を与える可能性があるため、推奨されません。

更新:

列挙型フィールドは定数であり、値が重複している可能性があることに注意してください。

enum Family {
    OFFSPRING(0),
    PARENT(1),
    GRANDPARENT(2),
    SIBLING(3),
    COUSING(4),
    UNCLE(4),
    AUNT(4);

    private final int hierarchy;

    private Family(int hierarchy) {
        this.hierarchy = hierarchy;
    }

    public int getHierarchy() {
        return hierarchy;
    }
}

hierarchyで何をしようとしているかによって、これは損害を与えるか有益になる可能性があります。

さらに、EnumFlagsを使用する代わりに、enum定数を使用して独自のEnumSetを構築できます。たとえば、

5
Leonardo Pina

列挙値間の関係のみを作成する場合は、実際にその他の列挙値を使用するトリックを使用できます。

public enum Person {
  GRANDPARENT(null),
  PARENT(GRANDPARENT),
  CHILD(PARENT);

  private final Person parent;

  private Person(Person parent) {
    this.parent = parent;
  }

  public final Parent getParent() {
    return parent;
  }
}

宣言しようとしているものの前に字句的に宣言された列挙値のみを使用できることに注意してください。そのため、これはリレーションシップが非循環有向グラフを形成する場合にのみ機能します(そしてそれらを宣言する順序は有効なトポロジカルソートです)。

5
Daniel Pryden

2番目のオプション(明示的な整数を使用)を使用して、数値がJavaではなくユーザーによって割り当てられるようにします。

3
gpeche

これはあなたの質問に対する直接的な答えではありません。あなたのユースケースにより良いアプローチ。これにより、次の開発者は、プロパティに割り当てられた値を変更してはならないことを明確に知ることができます。

列挙型をシミュレートする静的プロパティを持つクラスを作成します。

public class Persons {
    final public static int CHILD = 0;
    final public static int PARENT = 1;
    final public static int GRANDPARENT = 2;
}

次に、enumのように使用します。

Persons.CHILD

ほとんどの単純なユースケースで機能します。そうしないと、 valueOf()EnumSetEnumMap 、または values() などのオプションが欠落する可能性があります。

1
mzmrk

Java doc

この列挙定数の序数を返します(列挙宣言内の位置。初期定数にはゼロの序数が割り当てられます)。ほとんどのプログラマは、このメソッドを使用しません。 EnumSetやEnumMapなどの洗練された列挙ベースのデータ構造で使用するために設計されています。

列挙型の順序を変更することで序数を制御できますが、明示的に設定することはできません。回避策の1つは、必要な数の追加メソッドを列挙型で提供することです。

_enum Mobile {
   Samsung(400), Nokia(250),Motorola(325);

   private final int val;
  private Mobile (int v) { val = v; }
  public int getVal() { return val; }
}
_

この状況ではSamsung.ordinal() = 0ですが、Samsung.getVal() = 400です。

1
gati sahu