繁体   English   中英

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

[英]Case-insensitive matching of a string to a Java enum

Java提供valueOf()为每个方法Enum<T>对象,以便给出一个enum

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>类?

这种“通用” lookup()方法的签名类似于Enum.valueOf()方法,即:

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

并且它将为任何enum完全实现Day.lookup()方法的功能,而无需为每个enum重新编写相同的方法。

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

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"));
}

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

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

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

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

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

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

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

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");

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

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

您可以使用ClassgetEnumConstants()方法,如果Class表示枚举,则返回所有枚举类型的数组,否则返回null

如果此 Class 对象不表示枚举类型,则返回此枚举类的元素或 null。

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

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

我还没有测试过这个,但为什么不像这个SO 答案中提到的那样重载这些方法

 public enum Regular { NONE, HOURLY, DAILY, WEEKLY; public String getName() { return this.name().toLowerCase(); } }

并且它将为任何枚举完全实现 Day.lookup() 方法的功能,而无需为每个枚举重新编写相同的方法。

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

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 类,就像添加 values() 方法一样,那将会很好,但我认为没有办法做到这一点。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM