【问题标题】:java simple switch with enum带有枚举的java简单开关
【发布时间】:2014-02-10 23:31:52
【问题描述】:

我觉得我只是错过了一些东西,或者这可能不是枚举的使用。我几乎知道我可以使用枚举来清理这段代码:

    int bookTypeId = 1; //dynamic
    String bookTypeName;
    switch (bookTypeId) {
    case 1:
        bookTypeName = "Fantasy";
        break;
    case 2:
        bookTypeName = "Horror";
        break;
    case 3:
        bookTypeName = "Action";
        break;
    default:
        bookTypeName = "Error";
    }

所以我做到了,我将它存储在另一个类中,它看起来像:

public static enum BookType {
        HORROR("Horror"), FANTASY("Fantasy"), ACTION("Action"), ERROR("Error");

    private String name;

    BookType(String name) {
        this.name = name;
    }

    public String getType() {
        return name;
    }
}

现在像这样使用它:

switch (bookTypeId) {
    case 1:
        bookTypeName = MYConstants.BookType.FANTASY.getType();
        break;
    case 2:
        bookTypeName = MYConstants.BookType.HORROR.getType();
        break;
    case 3: 
        bookTypeName = MYConstants.BookType.ACTION.getType();
        break;
    default:
        bookTypeName = MYConstants.BookType.ERROR.getType();
    }

我想更进一步,清理我的这个 switch 语句的主类(这就是我开始研究枚举的原因,因为现在它似乎在做同样的事情)。

是否可以在枚举内移动此开关/案例?然后以诸如

之类的方式使用枚举
bookTypeName = MYConstants.BookType.getType(bookTypeId);

也可以使用 final 声明这个枚举(当我尝试时它目前正在抱怨),或者它已经是 final?

谢谢!

【问题讨论】:

  • 您将枚举放在MYConstants 中,而不是独立的,有什么原因吗?
  • 我认为Class 在这种情况下会更好。
  • @OP 你在这里有几个答案;如果它回答了您的问题,请接受其中之一。

标签: java enums


【解决方案1】:

类似下面的东西?

public static enum BookType {

    HORROR(1, "Horror"),
    FANTASY(2, "Fantasy"),
    ACTION(3, "Action");

    private static final Map<Integer, BookType> LOOKUP;

    static {
        LOOKUP = new HashMap<>();
        for (final BookType type : values()) {
            LOOKUP.put(type.id, type);
        }
    }

    public static BookType getById(final int id) {
        final BookType bt = LOOKUP.get(id);
        if (bt == null) {
            throw new IllegalArgumentException("Invalid book id " + id);
        }
        return bt;
    }

    private final int id;
    private final String name;

    BookType(final int id, final String name) {
        this.id = id;
        this.name = name;
    }

    public String getType() {
        return name;
    }
}

用法:

final BookType type = BookType.getById(bookTypeId);

您可以删除String 属性并覆盖toString()

@Override
public String toString() {
    final String name = name();
    return name.substring(0, 1) + name.substring(1).toLowerCase();
}

要回答您的最后一个问题,enum 不能是 finalenum 是语法糖;编译器将通过首先创建一个class BookType extends Enum&lt;BookType 和创建具有指定名称的新classstatic final 实例来对其进行脱糖。实际的enum 声明本身并不是真的 class 声明,因此不能是final。此外,如果您的enum 常量本身覆盖或实现方法(如在this example 中),那么每个enum 常量将是一个匿名类扩展Booktype - 如果enumfinal 并且被转置到BookType 类则不允许这种行为;而且原因并不完全清楚。

【讨论】:

    【解决方案2】:

    这真的取决于id和name之间关系的重要性。我会尝试一起消除 int id。如果这不可能,请考虑将其设为枚举中的一个字段。

    public static enum BookType {
      HORROR(1, "Horror"), FANTASY(2, "Fantasy"), ACTION(3, "Action"), ERROR(-1, "Error");
    
      private String name;
      private int typeCode;
    
      BookType(int typeCode, String name) {
        this.typeCode = typeCode;  
        this.name = name;
      }
    
      public String getName() {
          return name;
      }
    
      public int getTypeCode(){
        return typeCode;
      }
    
      public static BookType getFromTypeCode(int typeCode){
        for(BookType bookType : BookType.values()){
          if(bookType.getTypeCode() == typeCode){
            return bookType;
          }
        }
        return BookType.ERROR;
      }
    }
    

    【讨论】:

      【解决方案3】:

      我认为您正在寻找这种模式。

      public enum BookType {
      
          INVALID(0),
          HORROR(1),
          FANTASY(2),
          ACTION(3),
          ERROR(4);
      
          private int value;
      
          private BookType(int value) {
              this.value = value;
          }
      
          public int getValue() {
              return value;
          }
      
          public String toString(){
              return super.toString().toLowerCase();
          }
      
          public static BookType getInstance(int value) {
              for (BookType type : BookType.values()) {
                  if (value == type.value) {
                      return type;
                  }
              }
              return INVALID;
          }
      
          public static void main(String[] args){
              BookType b1 = BookType.HORROR;
              System.out.println(b1.toString());
      
              BookType b2 = BookType.getInstance(3);
              System.out.println(b2.toString());
          }
      
      }
      

      【讨论】:

      • 你不需要在枚举中添加一个整数字段来让它工作吗?
      • 啊,空对象模式和抛出异常之间的战斗开始了……
      【解决方案4】:

      你的开关在我看来已经够干净了。如果您想概括一下,我不会将硬编码的业务逻辑转移到另一个硬编码的业务逻辑块中。将其推送到配置文件或数据库。更简洁的方法是(某种)查找表。

      【讨论】:

        【解决方案5】:

        是的,你错过了一些东西,就在这里。这就是您所需要的全部

        enum Genre {
            Unknown,
            Fantasy,
            Horror,
            Action,
            Romance;
        }
        

        您确实不需要将结果与int 相互转换。

        您确实不需要将其与bookTypeId 来回转换,请使用valueOf

        如果您需要使书籍类型不仅仅是enum,请为其添加属性。

        您缺少的是枚举本身可以在程序的其他地方使用,可以按名称保存到数据库并通过valueOf方法恢复。

        让你的enum简单!

        而不是你的开关——它似乎得到了enumString 形式,只需这样做:

        String name = genre.name();
        

        【讨论】:

        • 除非我大错特错,否则枚举值真的应该全部大写。否则是个好帖子。
        • @ABoschman - 这是旧 C 时代的遗留物,当时很难分辨重要的是什么是不变的,什么不是。 Java 不是 C。
        • 哦,我也一直做错这些?我的教授有一些解释要做。
        • 好吧,如果你是对的,我错了,至少这是一个非常有争议的问题。我能找到的大多数来源都声明它们应该全部大写,包括此页面上的四张海报和 oracle 文档网站:docs.oracle.com/javase/tutorial/java/javaOO/enum.html
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-09
        • 1970-01-01
        • 2013-11-14
        • 1970-01-01
        • 2011-07-22
        • 1970-01-01
        相关资源
        最近更新 更多