没有枚举时常量的解决方案
- 使用
int
常量- 除了字段名外几乎没有描述性
- 不同类型的常量之间可以进行比较,甚至做运算
- 没有
toString
方法
- 使用
String
常量- 和
int
相同,不同类型的常量可以做运算 - 代码里会写魔法值
- 和
枚举的优势
- 枚举性能好,本质上是
int
值 - 提供了
Object
方法的实现,实现了Comparable
和Serializable
- 编译时的类型安全
- 允许添加任意的方法和域,并实现任意的接口
- 静态的
values()
方法可以按照声明顺序返回它的值数组
枚举的使用
-
因为枚举本身都是不变的,如果枚举里面有字段,则都应该是
final
的 -
如果一个枚举有普遍适用性,就应该成为一个顶层类。如果之被用在特定的顶层类中,则应该作为一个内部类
-
如果在枚举外面使用
switch
,通过判断枚举的类型决定特定的行为,则应该把行为定义在枚举内部public enum Operation { PLUS("+") { public double apply(double x, double y) { return x + y; } }, MINUS("-") { public double apply(double x, double y) { return x - y; } }, TIMES("*") { public double apply(double x, double y) { return x * y; } }, DIVIDE("/") { public double apply(double x, double y) { return x / y; } }; private final String symbol; Operation(String symbol) { this.symbol = symbol; } public abstract double apply(double x, double y); }
-
如果枚举的行为内部实现需要判断当前枚举,则可以使用策略枚举
比如一周有7天,工作日和周末付薪水的策略不一样。则可以定义两个枚举,一个表示一周的一天,一个表示这一天是工作日还是周末
enum PayrollDay { MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY), THURSDAY(WEEKDAY), FRIDAY(WEEKDAY), SATURDAY(WEEKEND), SUNDAY(WEEKEND); private final PayType payType; PayrollDay(PayType payType) { this.payType = payType; } int pay(int minutesWorked, int payRate) { return payType.pay(minutesWorked, payRate); } // The strategy enum type enum PayType { WEEKDAY { int overtimePay(int minsWorked, int payRate) { return minsWorked <= MINS_PER_SHIFT ? 0 : (minsWorked - MINS_PER_SHIFT) * payRate / 2; } }, WEEKEND { int overtimePay(int minsWorked, int payRate) { return minsWorked * payRate / 2; } }; abstract int overtimePay(int mins, int payRate); private static final int MINS_PER_SHIFT = 8 * 60; int pay(int minsWorked, int payRate) { int basePay = minsWorked * payRate; return basePay + overtimePay(minsWorked, payRate); } } }
-
枚举可以重写
toString
方法,如果重写的话,最好写一个fromString
方法,类比valueOf
private static final Map<String, Operation> stringToEnum = Stream.of(values()).collect( toMap(Object::toString, e -> e)); // Returns Operation for string, if any public static Optional<Operation> fromString(String symbol) { return Optional.ofNullable(stringToEnum.get(symbol)); }
-
枚举默认实现了
compareTo
方法,并且是final
的。它的实现就是比较枚举的定义顺序(ordinal
)public final int compareTo(E o) { Enum<?> other = o; Enum<E> self = this; if (self.getClass() != other.getClass() && // optimization self.getDeclaringClass() != other.getDeclaringClass()) throw new ClassCastException(); return self.ordinal - other.ordinal; }
思考
- 枚举的主要优点有:
- 是一个独立的类型
- 可以遍历
- 可以有自己的行为
- 如果我们需要在枚举里加入类似
fromString
的方法,有两个选择,一个是返回一个Optional
,另一个就是像valueOf
一样抛异常。我个人推荐抛异常,因为传入的内容找不到对应的Enum
应该是少数情况,不能因为偶然的情况,让其它所有使用的地方都加上冗余的判断ifPresent
- 对于
fromString
的实现,可以在初始化枚举的同时就构建好Map
,也可以每次调用的时候循环遍历查找。我自己更倾向于构建Map
,这种实现不会有多大的性能提升,就是看起来相对优雅一些 - 枚举转字符串一般有
toString
和name
两个选择,没有绝对的优先使用哪个。如果是用来记录当前枚举是哪个,推荐用name
,如果是为了显示,推荐用toString
。如果没有重写toString
这两个其实是一样的,toString
更适合用来作为显示 - 枚举里面嵌套一个枚举很少使用,只能说暂时作为一个思路,真的遇到了特定的情况就可以使用
网友评论