【问题标题】:Using a String to evaluate enum?使用字符串来评估枚举?
【发布时间】:2013-10-15 22:46:16
【问题描述】:

我正在尝试使用字符串来评估字符串内容是否等于我声明的枚举类型。但是,我在 Eclipse 中遇到错误,试图强制我将 nameOfMonth 创建为枚举常量。与其编写代码来明确声明一月为#1,二月为#2,等等,我似乎更容易使用枚举。有没有办法可以使用用户定义的字符串并将其与我的枚举进行比较?例如在下面的代码中,如果参数 String nameOfMonth 等于一月,我希望它提取索引位置并添加一个。

代码如下:

    package ProgrammingChallenges;

public class Month
{
    enum MONTH
    {
        January, February, March, April, May, June, July, August, September, October, November, December
    }

    private int monthNumber;

    public Month()
    {
        monthNumber = 1;
    }

    public Month(int monthNumber)
    {
        if (monthNumber < 1 || monthNumber > 12)
            this.monthNumber = 1;
        else
            this.monthNumber = monthNumber;

    }

    public Month(String nameOfMonth)
    {
        if(nameOfMonth.equals(MONTH.nameOfMonth))
            this.monthNumber = namOfMonth.ordinal() + 1;
    }

}

【问题讨论】:

  • 顺便说一句,Java 8 及更高版本现在内置了这样一个枚举:java.time.Month

标签: java eclipse enums constants


【解决方案1】:

Enum.valueOf

您可以使用枚举的valueOf 方法。

public Month(String nameOfMonth)
{
   this.monthNumber = MONTH.valueOf(nameOfMonth).ordinal() + 1;
}

这里不需要if语句,直接使用Java内置的valueOf枚举静态方法就可以得到字符串对应的枚举。如果nameOfMonth 不匹配枚举,则会抛出异常:

java.lang.IllegalArgumentException: No enum constant com.yourclass.yourenum.the_invalid_enum_name
    at java.lang.Enum.valueOf(Unknown Source)

【讨论】:

    【解决方案2】:
    public Month(String nameOfMonth)
    {
            this.monthNumber = Enum.valueOf(MONTH, nameOfMonth).ordinal() + 1;
    }
    

    根据Enum javadoc,如果用户传递了一个无效的字符串,这将抛出一个IllegalArgumentException,这似乎是一个合适的错误。 (注意MONTH.valueOf(str) 只是调用Enum.valueOf(MONTH, str))。

    但是,我不明白为什么您甚至需要单独的 Month 课程。为什么不直接将Month 改为enum?即使您在此类上有额外的方法,您也应该能够像在当前类实现中一样将这些方法添加到枚举中。从技术上讲,Java 枚举只是具有私有构造函数和一组静态定义的实例的类的特例,因此您应该能够使用枚举做任何您想做的事情。

    您可以在“默认”情况下使用Month.January,而不是当前的构造函数,Month.values()[i-1] 用于通过索引获取月份的情况,Month.valueOf(str) 用于使用字符串的情况.您还可以将静态辅助方法添加到包含这些案例的枚举中。这是我的想象:

    public enum Month {
        January, February, March, April, May, June, July, August, September, October, November, December;
    
        public static Month getDefault() {
            return January;
        }
    
        public static Month fromNumber(int monthNumber) {
            try {
                return Month.values()[monthNumber-1];
            } catch (ArrayIndexOutOfBoundsException e) {
                return getDefault();
            }
        }
    
        public static Month fromString(String nameOfMonth) {
            try {
                return valueOf(nameOfMonth);
            } catch (IllegalArgumentException e) {
                return getDefault();
            }            
        }
    }
    

    【讨论】:

    • 这是对西蒙回答的评论吗?
    • 既然可以简单地使用“MONTH.valueOf”,为什么还要使用Enum.valueOf
    • @SimonAndréForsberg - 它避免了额外的方法调用。 MONTH.valueOf 只是将它的参数传递给Enum.valueOf。您可以使用javap 轻松检查这一点。但是,JIT 编译器可能足够聪明,可以内联它,所以现在我想起来,它可能不会产生真正的影响。
    • 所以我想我应该在传递参数之前进行检查以确保它是有效的枚举?或者这种方法通常是不好的做法?
    • @SamHenderson - 你可以事先做个检查,或者如果不是,就抓住抛出的InvalidArgumentException。另外,检查我的编辑。我认为稍微重构一下并添加静态辅助方法在这里会有很多好处。
    【解决方案3】:

    对于那些感兴趣的人,这就是我最终解决问题的方式。如果没有您的所有精彩回答,我无法做到!

    MONTH[] months = MONTH.values();
    
    for (MONTH m : months)
            if (m.toString().equals(nameOfMonth))
                this.monthNumber = MONTH.valueOf(nameOfMonth).ordinal() + 1;
    

    【讨论】:

    • 这会遍历所有不必要的枚举值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多