Bye*_*Bye 26 java enums coding-style verbose
我有一个枚举:
public enum Persons {
CHILD,
PARENT,
GRANDPARENT;
}
Run Code Online (Sandbox Code Playgroud)
使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
vik*_*eve 44
如果您在以下ordinal方法中引用javadoc 方法Enum.java:
大多数程序员都没有使用这种方法.它设计用于复杂的基于枚举的数据结构,例如
java.util.EnumSet和java.util.EnumMap.
首先 - 阅读手册(本例中为javadoc).
其次 - 不要写脆弱的代码.枚举值可能在将来发生变化,您的第二个代码示例更加清晰和可维护.
如果在(PARENT和)之间插入一个新的枚举值,你绝对不希望为将来创建问题GRANDPARENT.
dav*_*xxx 10
第一种方式是不可理解的,因为你必须阅读使用枚举的代码来理解枚举的顺序很重要.
这很容易出错.
public enum Persons {
CHILD,
PARENT,
GRANDPARENT;
}
Run Code Online (Sandbox Code Playgroud)
第二种方式更好,因为它是自我解释的:
CHILD(0),
PARENT(1),
GRANDPARENT(2);
private SourceType(final Integer hierarchy) {
this.hierarchy = hierarchy;
}
Run Code Online (Sandbox Code Playgroud)
当然,枚举值的顺序应该与枚举构造函数参数提供的层次顺序一致.
它引入了一种冗余,因为枚举值和枚举构造函数的参数都传达了它们的层次结构.
但为什么会出现问题呢?
枚举旨在表示常量且不经常更改的值.
OP枚举用法说明了良好的枚举用法:
CHILD, PARENT, GRANDPARENT
Run Code Online (Sandbox Code Playgroud)
枚举不是为了表示经常移动的值.
在这种情况下,使用枚举可能不是最佳选择,因为它可能经常破坏使用它的客户端代码,并且除了它强制在每次修改枚举值时重新编译,重新打包和重新部署应用程序.
首先,您可能甚至不需要数字订单值 - 这就是为什么Comparable
和Enum<E>实现Comparable<E>.
如果由于某种原因确实需要数字订单值,是的,您应该使用ordinal().这就是它的用途.
对Java标准的做法Enums是声明的顺序,这就是为什么排序Enum<E>工具Comparable<E>,为什么
Enum.compareTo()是final.
如果您添加自己的非标准比较代码,该代码不使用
Comparable且不依赖于声明顺序,那么您只会混淆任何试图使用您的代码的人,包括您自己未来的自我.没有人会期望代码存在; 他们将希望Enum是Enum.
如果自定义订单与声明订单不匹配,那么查看声明的任何人都会感到困惑.如果它确实 (碰巧,此时此刻)与声明顺序相符,那么任何看着它的人都会期待这一点,而且在未来的某个日期,它会发生令人讨厌的震惊.(如果您编写代码(或测试)以确保自定义订单与声明顺序匹配,那么您只需加强其不必要的程度.)
如果您添加自己的订单值,则会为您自己创建维护问题:
hierarchy价值观是独一无二的如果您担心有人可能会在将来意外更改订单,请编写一个检查订单的单元测试.
总而言之,在第47项的不朽的话语中: 知道并使用这些库.
PS此外,不要Integer在你的意思使用int.
正如Joshua Bloch在Effective Java中所建议的那样,从序数中导出与枚举相关联的值并不是一个好主意,因为对枚举值排序的更改可能会破坏您编码的逻辑.
您提到的第二种方法完全遵循作者提出的建议,即将值存储在单独的字段中.
我会说你建议的替代方案肯定更好,因为它更加可扩展和可维护,因为你正在解耦枚举值的排序和层次结构的概念.
使用ordinal()是不推荐的,因为枚举声明中的更改可能会影响序数值.
更新:
值得注意的是,枚举字段是常量并且可以具有重复的值,即
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;
}
}
Run Code Online (Sandbox Code Playgroud)
根据您计划要做的事情,hierarchy这可能是有害的或有益的.
此外,您可以使用枚举常量来构建您自己的常量EnumFlags而不是使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,您只能使用在您尝试声明的枚举值之前声明的枚举值,因此这仅适用于您的关系形成非循环有向图(并且您声明它们的顺序是有效的拓扑排序).