【问题标题】:How to get a value from an enum without having a variable [duplicate]如何在没有变量的情况下从枚举中获取值[重复]
【发布时间】:2016-07-05 15:18:55
【问题描述】:

我有以下枚举器

public enum UserChoice {
    QUIT, LIST_BOOKS, CHECKOUT_BOOK, RETURN_BOOK, LIST_MOVIES,
    CHECKOUT_MOVIE, RETURN_MOVIE, USER_INFORMATION
}

我想在一个以 int 作为参数的 switch 语句中使用它。但是,我需要获取枚举的 int 值,所以我这样做:

try {
    int option = Reader.getUserOption();
} catch (InputMismatchException ex) {
    option = 8;
}

switch (option) {
    case UserChoice.QUIT.ordinal():
        break;
    case UserChoice.LIST_BOOKS.ordinal():
         Printer.printBooks(library);
         break;
    case UserChoice.CHECKOUT_BOOK.ordinal():
         // code
         break;
    case UserChoice.RETURN_BOOK.ordinal():
         // code
         break;
    case UserChoice.LIST_MOVIES.ordinal():
         Printer.printMovies(library);
         break;
    case UserChoice.CHECKOUT_MOVIE.ordinal():
         // code
         break;
    case UserChoice.RETURN_MOVIE.ordinal():
         // code
         break;
    case UserChoice.USER_INFORMATION.ordinal():
         System.out.println(currentUser);
         break;
    default:
         Printer.printInvalidOptionMessage();
         break;
    }

有什么方法可以将 int 转换为枚举值,或者我可以使用枚举来实现这一点。最后,我的意思是每个案例都有枚举器的名称,这样我就可以清楚地了解每个案例在做什么,因为之前我是使用 int 值来做的。

【问题讨论】:

  • 最后我在@Darth Android、@Xoce 和@Jim Garrison 的响应之后所做的就是从int 更改为UserChoice,所以UserChoice option = UserChoice.values()[Reader.getUserOption()];,并将option 设置为INVALID_OPTION(添加到枚举的新值)在 catch 块中。

标签: java enums


【解决方案1】:

INVALID_CHOICE 创建一个额外的枚举值并使用它。但更重要的是,您需要将用户输入与枚举的排序(和ordinal 值)完全分离。

这是一个如何做到这一点的示例。

public static enum UserChoice {
    /*
     * Establish the mapping between the enum value (the semantic action)
     * and the user's input.  This can be adapted to whatever form the user
     * input takes and is decoupled from the ordinal values.  It's all in 
     * one place here and a change here does not need a change anywhere else.
     */
    QUIT            ( 0), 
    LIST_BOOKS      ( 1), 
    CHECKOUT_BOOK   ( 2), 
    RETURN_BOOK     ( 3), 
    LIST_MOVIES     ( 4),
    CHECKOUT_MOVIE  ( 5), 
    RETURN_MOVIE    ( 6), 
    USER_INFORMATION( 7),
    INVALID_CHOICE  (Integer.MIN_VALUE);

    /*
     * The mapping, and its initialization, using the new features in Java 8
     */
    private static final Map<Integer,UserChoice> valueMap = Arrays.stream(UserChoice.values()).collect(Collectors.toMap(UserChoice::getValue, Function.identity()));

    /*
     * A method to convert from user input (int in this case) to the corresponding
     * enum value based on the mapping above.
     */
    public static UserChoice fromUserInput(int input) {
        return Optional.ofNullable(valueMap.get(input)).orElse(INVALID_CHOICE);
    }

    /*
     * Per-enum value and method
     */
    private final int userValue;
    private UserChoice(int userValue) { this.userValue = userValue; }
    public int getValue() { return this.userValue; }
}

/*
 * Simple test
 */
public static void main(String args[]) throws Exception 
{
    for (int i=0; i<10; i++)
    {
        UserChoice c = UserChoice.fromUserInput(i);
        System.out.printf("Input %d enum is %s\n", i, c.toString());
    }
}   

【讨论】:

  • option 是一个 int,用户通过控制台输入
  • 我已经重写了我的示例,以展示如何以一种将用户输入与序数位置完全分离的方式来执行此操作。虽然您可以使用序数,但我的示例完全封装了从用户输入到枚举值的映射,并且无论用户如何输入他们的选择都可以进行调整。
  • 你完全正确@Jim Garrison,所以你的答案值得验证
  • 谢谢。这个问题让我研究了新的 Java 8 流的东西。有点令人费解,但真的很酷。顺便说一句,这已经在 Eclipse 中进行了测试。玩得开心!
【解决方案2】:

您需要按索引查找枚举:

try {
    int option = Reader.getUserOption();
} catch (InputMismatchException ex) {
    option = 8;
}

switch (UserChoice.values()[option]) {
    case QUIT:
        break;
    case LIST_BOOKS:
         Printer.printBooks(library);
         break;
    case CHECKOUT_BOOK:
         // code
         break;
    case RETURN_BOOK:
         // code
         break;
    case LIST_MOVIES:
         Printer.printMovies(library);
         break;
    case CHECKOUT_MOVIE:
         // code
         break;
    case RETURN_MOVIE:
         // code
         break;
    case USER_INFORMATION:
         System.out.println(currentUser);
         break;
    default:
         Printer.printInvalidOptionMessage();
         break;
    }

我还建议不要存储索引,而是将枚举名称存储为字符串,因为在枚举中添加/删除/移动值时,序数可能会更改或移动。

【讨论】:

  • 谢谢!你的回答真的很好,解决了一切。
  • 如果您更改选项的顺序或数量,则会中断。您应该在枚举中将输入转换为枚举,以便将其全部集中在一个地方。枚举应该有一个静态方法来查找输入并返回枚举值,即UserChoice.fromUserInput(String input)
【解决方案3】:

如果Reader.getUserOption()UserChoice Enumerator 返回一个选项,则不需要强制转换...

示例:

switch (Reader.getUserOption()) {
            case CHECKOUT_MOVIE:
                
                break;
            case LIST_BOOKS:
                
                break;
            case QUIT:
                
                break;

            default:
                break;
        }

您当然需要在 try-catch 中执行 switch case。

编辑:

如果方法 getUserOption 返回一个 int 并且该 int 是枚举器中选项的序数表示:

退出,......,用户信息

0,......, 7

然后这样做:

switch (UserChoice.values()[Reader.getUserOption()]) {

【讨论】:

  • Reader.getUserOption() 返回用户给出的 int,所以我的问题是如何将该 int 转换为枚举值
  • 我更新了我的答案。看看,让我知道
  • 您的解决方案是有效的,但您知道我必须使用 QUIT 而不是 UserChoice.QUIT 才能编译
【解决方案4】:

请尝试UserChoice.values()[option] 选项从0 和option&lt;UserChoice.values().length 开始

【讨论】:

  • 重点是我想在代码中看到枚举值的名称。否则,我更喜欢使用我以前的(直接放在代码中的数字)
【解决方案5】:

UserChoice.values()[option] 应该这样做。你可以分别确定option &gt;= 0option &lt; UserChoice.values().length

请注意,有很多资源反对使用或存储ordinal,因为如果您添加、删除或重新排序枚举值,这些数字都会发生变化。如果数字是枚举的固有部分(如 RETURN_MOVIE 应始终解析为选项 6),您可能希望将其设为枚举常量的构造函数参数和属性,并通过单独的映射提供查找。

【讨论】:

  • 谢谢你的解决方案,让我知道如何解决它:)
猜你喜欢
  • 2020-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多