字符串与 Java 枚举的不区分大小写的匹配

Case-insensitive matching of a string to a Java enum

Java 为每个 Enum<T> 对象提供了一个 valueOf() 方法,所以给定一个 enum like

public enum Day {
  Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

可以像

那样进行查找
Day day = Day.valueOf("Monday");

如果传递给 valueOf() 的字符串与现有 Day 值不匹配(区分大小写),则会抛出 IllegalArgumentException

要进行不区分大小写的匹配,可以在 Day 枚举中编写一个自定义方法,例如

public static Day lookup(String day) {
  for (Day d : Day.values()) {
    if (d.name().equalsIgnoreCase(day)) {
      return type;
    }
  }
  return null;
}

是否有任何通用的方法,而不使用缓存值或任何其他额外的对象,只编写一次像上面那样的静态 lookup() 方法(即,不是每个 enum),鉴于 values() 方法在编译时隐式添加到 Enum<E> class?

这种 "generic" lookup() 方法的签名类似于 Enum.valueOf() 方法,即:

public static <T extends Enum<T>> T lookup(Class<T> enumType, String name);

并且它将为任何 enum 实现 Day.lookup() 方法的功能,而无需为每个 enum.[=32= 重写相同的方法]

您可以使用 Class's getEnumConstants() method,其中 returns 所有枚举类型的数组,如果 Class 表示枚举,否则 null

Returns the elements of this enum class or null if this Class object does not represent an enum type.

您的增强 for 循环行如下所示:

for (T d : enumType.getEnumConstants()) {

我认为最简单安全的方法是:

Arrays.stream(Day.values())
    .filter(e -> e.name().equalsIgnoreCase(dayName)).findAny().orElse(null);

或者如果您想使用 class 对象,则:

Arrays.stream(enumClass.getEnumConstants())
    .filter(e -> (Enum)e.name().equalsIgnoreCase(dayName)).findAny().orElse(null);

我发现获得泛型的特殊混合有点棘手,但这很有效。

public static <T extends Enum<?>> T searchEnum(Class<T> enumeration,
        String search) {
    for (T each : enumeration.getEnumConstants()) {
        if (each.name().compareToIgnoreCase(search) == 0) {
            return each;
        }
    }
    return null;
}

例子

public enum Horse {
    THREE_LEG_JOE, GLUE_FACTORY
};

public static void main(String[] args) {
    System.out.println(searchEnum(Horse.class, "Three_Leg_Joe"));
    System.out.println(searchEnum(Day.class, "ThUrSdAy"));
}

一个通用的解决方案是遵守常量大写 的约定。 (或者在您的特定情况下使用查找字符串的大写字母)。

public static <E extends Enum<E>> E lookup(Class<E> enumClass,
        String value) {
    String canonicalValue.toUpperCase().replace(' ', '_');
    return Enum<E>.valueOf(enumClass, canonicalValue);
}

enum Day(MONDAY, ...);
Day d = lookup(Day,class, "thursday");

and it would implement exactly the functionality of the Day.lookup() method for any enum, without the need to re-write the same method for each enum.

也许您可以编写一个实用程序 class 来执行此操作,如下所示。

public class EnumUtil {

    private EnumUtil(){
        //A utility class
    }

    public static <T extends Enum<?>> T lookup(Class<T> enumType,
                                                   String name) {
        for (T enumn : enumType.getEnumConstants()) {
            if (enumn.name().equalsIgnoreCase(name)) {
                return enumn;
            }
        }
        return null;
    }

    // Just for testing
    public static void main(String[] args) {
        System.out.println(EnumUtil.lookup(Day.class, "friday"));
        System.out.println(EnumUtil.lookup(Day.class, "FrIdAy"));
    }

}

enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

如果 Java 中有一种方法可以让我们通过隐式添加方法来扩展 Enum class 就像添加 values() 方法一样,那就太好了,但我没有认为有办法做到这一点。

对于 Android 和相对较短的枚举,我执行简单的循环并比较忽略大小写的名称。

public enum TransactionStatuses {
    public static TransactionStatuses from(String name) {
        for (TransactionStatuses status : TransactionStatuses.values()) {
            if (status.name().equalsIgnoreCase(name)) {
                return status;
            }
        }
        return null;
    }
}

从版本 3.8 开始,apache commons-lang EnumUtils 有两个方便的方法:

  • getEnumIgnoreCase(final Class<E> enumClass, final String enumName)
  • isValidEnumIgnoreCase(final Class<E> enumClass, final String enumName)

我正在使用这种方式将字符串与 java 枚举进行不区分大小写的匹配 Day[] days = Day.values(); for(Day day: days) { System.out.println("MONDAY".equalsIgnoreCase(day.name())); }

我还没有对此进行测试,但为什么不重载本文中提到的这些方法

public enum Regular {
    NONE,
    HOURLY,
    DAILY,
    WEEKLY;

    public String getName() {
        return this.name().toLowerCase();
    }    
}

我相信这个,或者类似的解决方案还没有发布。我更喜欢去这里(绝对不需要 'lookup',只需要一个更聪明的 valueOf。另外,作为奖励,枚举值都是大写的,因为我们以前的 c++ 人认为他们应该是...

public enum Day {
    MONDAY("Monday"), 
    TUESDAY("Tuesday"), 
    WEDNESDAY("Wednesday"),
    THURSDAY("Thursday"), 
    FRIDAY("Friday"),
    SATURDAY("Saturday"),
    SUNDAY("Sunday"); 

    public static Day valueOfIgnoreCase(String name) {
         return valueOf(name.toUpperCase());
    }

    private final String displayName; 

    Day(String displayName) {
        this.displayName = displayName;
    }

    @Override
    public String toString() {
        return this.displayName; 
    }
}

然后:

Day day = Day.valueOfIgnoreCase("mOnDay"); 
System.out.println(day); 

>>> Monday