美文网首页
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. 枚举里面嵌套一个枚举很少使用,只能说暂时作为一个思路,真的遇到了特定的情况就可以使用

    相关文章

      网友评论

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

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