如何在Java中通过字符串值获取枚举值

2365

假设我有一个枚举类型,内容如下:

public enum Blah {
    A, B, C, D
}

我想要根据一个字符串找到对应的枚举值,例如 "A" 对应的是 Blah.A。有什么方法可以实现吗?

Enum.valueOf() 是我需要的方法吗?如果是,我该如何使用它?


1
这里有一个解决方案,不仅可以忽略大小写地执行此操作,而且将解决方案从O(N)移动到O(1):https://dev59.com/Ll4c5IYBdhLWcg3wFW6N#74408971 - chaotic3quilibrium
32个回答

6

使用:

public enum MyEnum {
    FIRST,
    SECOND,
    THIRD;

    public static Optional<MyEnum> fromString(String value) {
        try {
            return Optional.of(MyEnum.valueOf(value));
        }catch(Exception e) {
            return Optional.empty();
        }
    }
}

5

Enum valueOf()

枚举类在编译时会自动获得一个静态的valueOf()方法。可以使用valueOf()方法来获取给定String值的枚举类实例。

例如:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.TWO.name());
    }
    enum Strings {
        ONE, TWO, THREE
    }
}

4

Michael Myers的回答的基础上,有一个实用工具...

valueOf() 在不喜欢其输入的情况下会抛出两种不同的异常。

  • IllegalArgumentException
  • NullPointerExeption

如果您的需求是不能保证您的字符串一定与枚举值匹配,例如,如果字符串数据来自数据库并可能包含旧版本的枚举,则通常需要处理这些问题...

因此,这里有一个可重复使用的方法,允许我们定义一个默认的枚举值,如果我们传递的字符串不匹配,则返回该值。

private static <T extends Enum<T>> T valueOf( String name , T defaultVal) {
        try {
            return Enum.valueOf(defaultVal.getDeclaringClass() , name);
        } catch (IllegalArgumentException | NullPointerException e) {
            return defaultVal;
        }
    }

使用方法如下:

public enum MYTHINGS {
    THINGONE,
    THINGTWO
}

public static void main(String [] asd) {
  valueOf("THINGTWO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGTWO
  valueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE
}

3
作为一个“switch”版本尚未被提及,我介绍一下它(重用OP的枚举):
  private enum Blah {
    A, B, C, D;

    public static Blah byName(String name) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          throw new IllegalArgumentException(
            "No enum constant " + Blah.class.getCanonicalName() + "." + name);
      }
    }
  }

由于这不会为valueOf(String name)方法提供任何附加值,所以只有在我们想要不同的行为时才有意义定义一个额外的方法。如果我们不想引发IllegalArgumentException,我们可以将实现更改为:

  private enum Blah {
    A, B, C, D;

    public static Blah valueOfOrDefault(String name, Blah defaultValue) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          if (defaultValue == null) {
            throw new NullPointerException();
          }
          return defaultValue;
      }
    }
  }

通过提供默认值,我们保持了Enum.valueOf(String name)contract,避免了抛出IllegalArgumentException并确保在任何情况下都不会返回null。因此,如果名称为null,或者在使用defaultdefaultValuenull,我们将抛出NullPointerException。这就是valueOfOrDefault的工作原理。
这种方法采用了Map接口的设计,该接口提供了一个方法Map.getOrDefault(Object key, V defaultValue),自Java 8以来一直存在。

3

我正在寻找一种方法来获取“blah”名称,而不是其值(即不是文本)。根据Manu的回答,我发现以下代码很有用:

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

private String text;

Blah(String text) {
    this.text = text;
}

public String getText() {
    return this.text;
}

public static Blah valueOfCode(String blahCode) throws IllegalArgumentException {
    Blah blah = Arrays.stream(Blah.values())
            .filter(val -> val.name().equals(blahCode))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("Unable to resolve blah: " + blahCode));

    return blah;
}

}


2
public enum ToggleStatusUpdate {
    OFF("off", 1),
    ON("on", 2);
    
    private final String name;
    private final int position;
    
    private ToggleStatusUpdate(String name, int position) {
        this.name = name;
        this.position = position;
    }

    public String getName() {
        return name;
    }

    public int getPosition() {
        return position;
    }
    
    public static int getPositionForName(String name) {
        for(ToggleStatusUpdate toggleStatusUpdate : ToggleStatusUpdate.values()) {
            if (toggleStatusUpdate.getName().equals(name)) {
                return toggleStatusUpdate.getPosition();
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        System.out.println(ToggleStatusUpdate.getPositionForName("off"));
    }
}

我们可以创建一个静态映射表,将名称映射到枚举值,而不是每次调用 getPositionForName() 方法时都进行迭代。这样可以预先计算映射关系,并且每次方法调用时都不需要迭代枚举值。由于我们从映射表中获取它,所以它的时间复杂度为 O(1)。 - Kunal Varpe

1

另一个以相反方式捕获的实用程序。使用标识该枚举的值,而不是其名称。

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.EnumSet;

public class EnumUtil {

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose a 
     * public method return value of this Enum is 
     * equal to <code>valor</code>.<br/>
     * Such method should be unique public, not final and static method 
     * declared in Enum.
     * In case of more than one method in match those conditions
     * its first one will be chosen.
     * 
     * @param enumType
     * @param value
     * @return 
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value) {
        String methodName = getMethodIdentifier(enumType);
        return from(enumType, value, methodName);
    }

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose  
     * public method <code>methodName</code> return is 
     * equal to <code>value</code>.<br/>
     *
     * @param enumType
     * @param value
     * @param methodName
     * @return
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value, String methodName) {
        EnumSet<E> enumSet = EnumSet.allOf(enumType);
        for (E en : enumSet) {
            try {
                String invoke = enumType.getMethod(methodName).invoke(en).toString();
                if (invoke.equals(value.toString())) {
                    return en;
                }
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    private static String getMethodIdentifier(Class<?> enumType) {
        Method[] methods = enumType.getDeclaredMethods();
        String name = null;
        for (Method method : methods) {
            int mod = method.getModifiers();
            if (Modifier.isPublic(mod) && !Modifier.isStatic(mod) && !Modifier.isFinal(mod)) {
                name = method.getName();
                break;
            }
        }
        return name;
    }
}

例子:

public enum Foo {
    ONE("eins"), TWO("zwei"), THREE("drei");

    private String value;

    private Foo(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

EnumUtil.from(Foo.class, "drei") 返回 Foo.THREE,因为它将使用 getValue 来匹配 "drei",这是 Foo 中唯一的公共、非 final 和非静态方法。 如果 Foo 有多个公共、非 final 和非静态方法,例如 getTranslate 返回 "drei",则可以使用另一个方法:EnumUtil.from(Foo.class, "drei", "getTranslate")


1
使用流(Stream)实现Java 8的答案和评论的组合。 它创建了一个静态Map进行查找,并提供默认值以避免空检查。
public enum Blah {
    A, B, C, D, INVALID

    private static final Map<String, Blah> ENUM_MAP = Stream.of(Blah.values())
            .collect(Collectors.toMap(Enum::name, Function.identity()));

    public static Blah of(final String name) {
        return ENUM_MAP.getOrDefault(name, INVALID);
    }
}

// e.g.
Blah.of("A");
A

Blah.of("X")
INVALID

0

我喜欢使用这种过程将命令作为字符串解析成枚举。通常我会将其中一个枚举设置为“未知”,这样当其他枚举(即使是不区分大小写的)未被找到时,就可以返回该值,而不是 null(表示没有值)。因此我采用这种方法。

static <E extends Enum<E>> Enum getEnumValue(String what, Class<E> enumClass) {
    Enum<E> unknown=null;
    for (Enum<E> enumVal: enumClass.getEnumConstants()) {  
        if (what.compareToIgnoreCase(enumVal.name()) == 0) {
            return enumVal;
        }
        if (enumVal.name().compareToIgnoreCase("unknown") == 0) {
            unknown=enumVal;
        }
    }  
    return unknown;
}

0

获取枚举名称的最快方法是在应用程序启动时创建一个枚举文本和值的映射表,然后通过调用函数Blah.getEnumName()来获取名称:

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;
    private HashMap<String, String> map;
    Blah(String text) {
    this.text = text;
    }

    public String getText() {
      return this.text;
    }

    static{
      createMapOfTextAndName();
    }

    public static void createMapOfTextAndName() {
        map = new HashMap<String, String>();
        for (Blah b : Blah.values()) {
             map.put(b.getText(),b.name());
        }
    }
    public static String getEnumName(String text) {
        return map.get(text.toLowerCase());
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接