私は列挙型を持っています:
_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;
}
}
_
Enum.Java
のordinal
メソッドについてjavadocを参照する場合:
ほとんどのプログラマは、このメソッドを使用しません。
Java.util.EnumSet
やJava.util.EnumMap
など、洗練された列挙ベースのデータ構造で使用するために設計されています。
まず、マニュアル(この場合はjavadoc)を読んでください。
第二に、もろいコードを書かないでください。列挙値は将来変更される可能性があり、2番目のコード例はさらに多くのclearおよびmaintainableです。
新しい列挙値が(たとえば)PARENT
とGRANDPARENT
の間に挿入される場合、将来の問題を作成することは絶対に望まないでしょう。
最初の方法は、列挙型の順序が重要であることを理解するために列挙型が使用されているコードを読む必要があるため、直接理解できません。
非常にエラーが発生しやすいです。
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値が変更されるたびにアプリケーションの再コンパイル、再パッケージ化、および再デプロイを強制するため、おそらく最適な選択ではありません。
Effective JavaでJoshua Blochが示唆したように、enum値の順序を変更するとエンコードしたロジックが壊れる可能性があるため、enumに関連付けられた値をその序数から導出することはお勧めできません。
あなたが言及する2番目のアプローチは、著者が提案するものに正確に従います。それは、別のフィールドに値を保存することです。
列挙値の順序と階層の概念を切り離すので、あなたが提案した代替案は、拡張性と保守性が高いため、間違いなく優れていると思います。
最初に、おそらく数値の順序値さえ必要ありません-それが Comparable
の目的であり、Enum<E>
はComparable<E>
を実装します。
何らかの理由で数値の順序値が必要な場合do、はい、ordinal()
を使用する必要があります。それが目的です。
Java Enums
の標準的な方法は、宣言順序でソートすることです。これがEnum<E>
がComparable<E>
を実装し、Enum.compareTo()
がfinal
である理由です。
Comparable
を使用せず、宣言の順序に依存しない独自の非標準の比較コードを追加すると、コードを使用しようとする他の人(自分自身の将来の自己を含む)を混乱させるだけです。そのコードが存在することを誰も期待していません。彼らはEnum
がEnum
であることを期待しています。
カスタムの順序が宣言の順序と一致しない場合、宣言を見る人は混乱するでしょう。 does(現時点では)が宣言順序と一致する場合、それを見る人はそれを期待するようになり、彼らは将来のある日にそれが起こらないとき、厄介なショックを受けるでしょう。 (カスタムオーダーが宣言オーダーと一致することをensureにコード(またはテスト)を記述した場合、それがいかに不要であるかを補強するだけです。)
独自の注文値を追加すると、自分でメンテナンスの頭痛の種になります。
hierarchy
の値が一意であることを確認する必要があります将来、誰かが誤って順序を変更するのではないかと心配している場合は、順序を確認する単体テストを作成してください。
要するに、 Item 47 :の不滅の言葉では、ライブラリを知って使用します。
追伸また、Integer
を意味する場合は、int
を使用しないでください。 ????
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
を構築できます。たとえば、
列挙値間の関係のみを作成する場合は、実際にその他の列挙値を使用するトリックを使用できます。
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;
}
}
宣言しようとしているものの前に字句的に宣言された列挙値のみを使用できることに注意してください。そのため、これはリレーションシップが非循環有向グラフを形成する場合にのみ機能します(そしてそれらを宣言する順序は有効なトポロジカルソートです)。
2番目のオプション(明示的な整数を使用)を使用して、数値がJavaではなくユーザーによって割り当てられるようにします。
これはあなたの質問に対する直接的な答えではありません。あなたのユースケースにより良いアプローチ。これにより、次の開発者は、プロパティに割り当てられた値を変更してはならないことを明確に知ることができます。
列挙型をシミュレートする静的プロパティを持つクラスを作成します。
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() 、 EnumSet 、 EnumMap 、または values() などのオプションが欠落する可能性があります。
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
です。