美文网首页
Effective Java - 用enum代替int常量

Effective Java - 用enum代替int常量

作者: DZQANN | 来源:发表于2022-06-28 22:56 被阅读0次

没有枚举时常量的解决方案

  1. 使用int常量
    • 除了字段名外几乎没有描述性
    • 不同类型的常量之间可以进行比较,甚至做运算
    • 没有toString方法
  2. 使用String常量
    • int相同,不同类型的常量可以做运算
    • 代码里会写魔法值

枚举的优势

  1. 枚举性能好,本质上是int
  2. 提供了Object方法的实现,实现了ComparableSerializable
  3. 编译时的类型安全
  4. 允许添加任意的方法和域,并实现任意的接口
  5. 静态的values()方法可以按照声明顺序返回它的值数组

枚举的使用

  1. 因为枚举本身都是不变的,如果枚举里面有字段,则都应该是final

  2. 如果一个枚举有普遍适用性,就应该成为一个顶层类。如果之被用在特定的顶层类中,则应该作为一个内部类

  3. 如果在枚举外面使用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);
    }
    
  4. 如果枚举的行为内部实现需要判断当前枚举,则可以使用策略枚举

    比如一周有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);
            }
        }
    }
    
  5. 枚举可以重写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));
    }
    
  6. 枚举默认实现了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;
    }
    

思考

  1. 枚举的主要优点有:
    • 是一个独立的类型
    • 可以遍历
    • 可以有自己的行为
  2. 如果我们需要在枚举里加入类似fromString的方法,有两个选择,一个是返回一个Optional,另一个就是像valueOf一样抛异常。我个人推荐抛异常,因为传入的内容找不到对应的Enum应该是少数情况,不能因为偶然的情况,让其它所有使用的地方都加上冗余的判断ifPresent
  3. 对于fromString的实现,可以在初始化枚举的同时就构建好Map,也可以每次调用的时候循环遍历查找。我自己更倾向于构建Map,这种实现不会有多大的性能提升,就是看起来相对优雅一些
  4. 枚举转字符串一般有toStringname两个选择,没有绝对的优先使用哪个。如果是用来记录当前枚举是哪个,推荐用name,如果是为了显示,推荐用toString。如果没有重写toString这两个其实是一样的,toString更适合用来作为显示
  5. 枚举里面嵌套一个枚举很少使用,只能说暂时作为一个思路,真的遇到了特定的情况就可以使用

相关文章

  • EffectiveJava第6章-枚举和注解

    第30条:用enum代替int常量 (1)int枚举模式 比较脆弱,如果与枚举常量关联的int发生了变化,客户端需...

  • Effective java笔记(五),枚举和注解

    30、用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型。在java没有引入枚举类型前,表示枚...

  • EffectiveJava-5-枚举和注解

    用enum代替int常量 1. int枚举: 引入枚举前,一般是声明一组具名的int常量,每个常量代表一个类型成员...

  • 枚举和注解

    30,用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型。 与int常量相比,枚举的优势是不言...

  • effective java 第三周

    第6章 枚举和注解 第30条:用 enum 代替 int 常量 在没有 enum 之前表示枚举类型的常用模式时声...

  • Effective Java 2

    五、枚举和注解 30、用enum代替int常量 132,135 31、用实例域代替序数 不要依赖于枚举的顺序编程 ...

  • Effective Java(第3版)第6章总结

    第34条:用 enum 代替 int 常量 用枚举的情况一般都是某个类别的常量。比如星期、月份、颜色等等。 第35...

  • 使用enum代替int常量

    在枚举类型出现之前,一般都常常使用int常量或者String常量表示列举相关事物。如: 针对int常量以下不足: ...

  • Kotlin enum类与companion之间的问题 Clas

    大家都知道Android推荐用常量代替枚举enum,这个问题先不讨论。 先假设如果一定要用enum假设java情况...

  • 第30条:用enum代替int常量

    枚举类型是指由一组固定的常量组成合法值的类型,例如一年中的季节,太阳系中的行星或者一副牌中的花色。在编程语言...

网友评论

      本文标题:Effective Java - 用enum代替int常量

      本文链接:https://www.haomeiwen.com/subject/ppixbrtx.html