为什么要定义枚举类?
有时候一个类的某些变量的值是有限的、或者固定的,使用数字,可读性差、经常需要去定义的地方查看它的意义,如果代码里没有注释,将会是很痛苦的!此时若定义枚举类,枚举类的名称命名时涵盖该变量的意义,枚举项替代原有的数字或者其他常量项,在读、写代码时友好性大大增加!
示例枚举类定义,将枚举类的方法直接以static修饰!
public class ProductRefEnum {
@Getter
@AllArgsConstructor
public enum FunctionType {
/**
* 功能定义来源枚举,0:模板引入,1:自定义
*/
MODEL_REF(0, "模板引入"),
CUSTOM(1, "自定义");
public Integer code;
public String msg;
private static HashMap<Integer, ProductRefEnum.NodeType> data = new HashMap<>();
static {
for (ProductRefEnum.FunctionType type : ProductRefEnum.FunctionType.values()) {
data.put(type.code, type);
}
}
public static ProductRefEnum.FunctionType parse(Integer code) {
if (data.containsKey(code)) {
return data.get(code);
}
return null;
}
}
public enum GoodsType {
WEIGH(1, "按重计价"),
SIN(2, "按份计价");
GoodsType(int code, String value) {
this.code = code;
this.value = value;
}
private int code;
private String value;
public int getCode() {
return this.code;
}
public String getValue() {
return this.value;
}
}
}
为什么不用静态常量来替代枚举类呢?
使用常量会有以下几个缺陷:
1. 类型不安全。若一个方法中要求传入季节这个参数,用常量的话,形参就是int类型,开发者传入任意类型的int类型值就行,但是如果是枚举类型的话,就只能传入枚举类中包含的对象。
2. 没有命名空间。开发者要在命名的时候以SEASON_开头,这样另外一个开发者再看这段代码的时候,才知道这四个常量分别代表季节。
和静态常量比起来,枚举类更加直观,类型安全!
枚举类遍历
/**
* 枚举类遍历测试
*
*/
@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class EnumIteration {
enum FourteenEnum {
a,b,c,d,e,f,g,h,i,j,k,l,m,n;
static final FourteenEnum[] VALUES;
static {
VALUES = values();
}
}
@Benchmark
public void valuesEnum(Blackhole bh) {
for (FourteenEnum value : FourteenEnum.values()) {
bh.consume(value.ordinal());
}
}
@Benchmark
public void enumSetEnum(Blackhole bh) {
for (FourteenEnum value : EnumSet.allOf(FourteenEnum.class)) {
bh.consume(value.ordinal());
}
}
@Benchmark
public void cacheEnums(Blackhole bh) {
for (FourteenEnum value : FourteenEnum.VALUES) {
bh.consume(value.ordinal());
}
}
}
很明显使用缓存后的遍历速度是最快的,使用 EnumSet
遍历效率是最低的,这很好理解,数组的遍历效率是大于哈希表的。
可能你会觉得这里使用 values()
缓存和直接使用 Enum.values()
的效率差异很小,其实在某些调用频率很高的场景下是有很大区别的,在 Spring 框架中,曾使用 Enum.values()
这种方式在每次响应时遍历 HTTP 状态码枚举类,这在请求量大时造成了不必要的性能开销,后来进行了 values()
缓存优化。