【问题标题】:Using integer values and String identifier in an Enum在枚举中使用整数值和字符串标识符
【发布时间】:2013-09-05 16:59:36
【问题描述】:

所以我目前有两个枚举:

public enum AuthorizationLevel 
    {   
        FULL,
        HALF,
        NONE;
    };


public enum DatabaseLoggingLevel
{
    HIGH,
    MED,
    LOW,
    AUTH_ONLY,
    NONE
}

我希望能够将整数与枚举中的值相关联,这样我就可以编写如下代码:

if(databaseLoggingLevel < ClassName.DatabaseLoggingLevel.HIGH) return;

这只是为了在级别低于HIGH 时禁用某些日志记录。我考虑过创建一个辅助函数,该函数使用 switch 语句返回与每个枚举值关联的整数值,但这似乎很棘手。有什么我遗漏的吗?

【问题讨论】:

    标签: java enums


    【解决方案1】:

    您可以在枚举中添加整数实例字段,并添加参数化构造函数:

    enum AuthorizationLevel {
    
        FULL(1), HALF(2), NONE(3);
    
        private final int level;
    
        private AuthorizationLevel(int level) {
            this.level = level;
        }
    
        public int getLevel() {
            return level;
        }
    };
    

    请注意,有一个ordinal() 方法可以为您提供枚举常量的位置,但您应该避免使用它。再次引用Effective Java Item - 31 (Use instance fields instead of ordinal)

    如果常量被重新排序,numberOfMusicians 方法将 休息。如果您想添加与 你已经使用过的 int 值,你就不走运了。

    此外,您不能为 int 值添加常量而不添加 所有介入的 int 值的常量。例如,假设你 想添加一个代表三重四重奏的常数,它包括 十二个音乐家。合奏没有标准术语 由 11 位音乐家组成,所以你不得不添加一个假人 未使用的 int 值 (11) 的常量。充其量,这很丑陋。如果很多 未使用 int 值,这是不切实际的。

    【讨论】:

    • 是的,正是我想要的。我以为我从某个地方记得这种语法。谢谢!时间到了我会接受的。
    • 对于枚举,我通常建议在字段上使用“final”关键字,例如private final int val;
    • @StormeHawke。是的,我错过了。我也喜欢这种方式。
    【解决方案2】:

    修改枚举的构造函数以添加整数值。

    public enum DatabaseLoggingLevel {
      HIGH(1),
      MED(2),
      LOW(3),
      AUTH_ONLY(4),
      NONE(5);
    
      private final Integer value;
    
      //For getByValue(). See Rohit's comment
      private static final DatabaseLoggingLevel[] VALUES = DatabaseLoggingLevel.values();
    
      private DatabaseLoggingLevel(Integer value) {
        this.value = value;
      }
    
      public Integer getValue() {
        return this.value;
      }
    
      //Bonus : getter by value:
      public static DatabaseLoggingLevel getByValue(Integer value) {
        for(DatabaseLoggingLevel e: VALUES) {
          if(e.getValue().equals(value)) {
            return e;
          }
        }
        return null;
      }
    }
    

    【讨论】:

    • 1.您在最后一个枚举常量之后缺少一个分号。 2. 为什么使用Integer 而不是int? 3. DatabaseLoggingLevel.values() 将在每次调用该方法时创建一个数组。最好将数组缓存在字段本身中。 4. 如果值是字符串,那么该方法确实是一个奖励。如果是整数,我看不出它有什么主要用途。
    • 1:已编辑。 2:我不喜欢文字,我个人的选择。 3:编辑。 4:这个已经存在:Enum#valueOf(String s);
    • 2.我不喜欢文字 - 我说的是原始类型 int 而不是包装类。如果你不喜欢原始类型,我为你和你的程序员同事感到难过。您最终可能会创建不必要的对象。
    • Primitives vs Objects 是一场不会发生在这个线程中的辩论。始终使用对象是我个人的设计选择(消费算法除外)。当我想要一些性能时,我用 C 编写代码。
    【解决方案3】:
    public enum DatabaseLoggingLevel
    {
        HIGH(1),
        MED(2),
        LOW(3),
        AUTH_ONLY(4),
        NONE(5)
    
        private int code;
    
        private DatabaseLoggingLevel(int code) {
          this.code = code;
        }
    
        public int getCode() { return code; }
    
    }
    

    【讨论】:

      【解决方案4】:

      使用ordinal() method。它为您提供了值在枚举中的位置。

      【讨论】:

      • 相当危险。如果在枚举中添加一个值,它将修改所有的ordinal()。
      【解决方案5】:

      与其按照“enums 是数字”来编程,不如按照“enums 是聪明的”来编程。您可以将数字与enums 相关联(毕竟,enums 是常规 Java 类的实例),但将该数字设为私有。然后可以将此方法添加到enum

      public boolean isAboveOrEqualTo(DatabaseLoggingLevel level) {
          ...
      }
      

      那么您的条件将如下所示:

      if (databaseLoggingLevel.isAboveOrEqualTo(ClassName.DatabaseLoggingLevel.HIGH)) {
          ...
      }
      

      以下是如何将数字与枚举关联的说明:link

      【讨论】:

      • 虽然这肯定更面向对象,但与简单的整数比较相比,它的冗长程度相当令人反感。也就是实际写isAboveOrEqualTo方法,而不是if语句中的实际比较。
      • @thatidiotguy 暴露ints 的问题在于,这样做会泄露太多实现,人们可能宁愿躲在enum 后面。如果信息隐藏不是一个目标,那么首先就没有理由引入enum,因为符号int 常量就足够了。
      【解决方案6】:

      虽然给出的两个答案都可以满足您的需求,但我建议您将 Log4J 作为滚动您自己的日志记录级别的替代方法

      http://www.tutorialspoint.com/log4j/log4j_overview.htm

      【讨论】:

      • 我用它来记录文本。这是更具体的应用程序,但谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-15
      • 1970-01-01
      • 1970-01-01
      • 2013-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多