如何从字符串值查找Java枚举?

我想从它的字符串值(或者可能是任何其他值)中查找一个枚举。我已经尝试了下面的代码,但它不允许在初始化程序中使用静态。有没有简单的方法?

public enum Verbosity {


BRIEF, NORMAL, FULL;


private static Map<String, Verbosity> stringMap = new HashMap<String, Verbosity>();


private Verbosity() {
stringMap.put(this.toString(), this);
}


public static Verbosity getVerbosity(String key) {
return stringMap.get(key);
}
};
331674 次浏览

你不能用值()

编辑:顺便说一句,没有什么可以阻止你在枚举中使用static{}。

你很接近了。对于任意值,请尝试如下操作:

public enum Day {


MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;


private final String abbreviation;


// Reverse-lookup map for getting a day from an abbreviation
private static final Map<String, Day> lookup = new HashMap<String, Day>();


static {
for (Day d : Day.values()) {
lookup.put(d.getAbbreviation(), d);
}
}


private Day(String abbreviation) {
this.abbreviation = abbreviation;
}


public String getAbbreviation() {
return abbreviation;
}


public static Day get(String abbreviation) {
return lookup.get(abbreviation);
}
}

使用自动为每个枚举创建的valueOf方法。

Verbosity.valueOf("BRIEF") == Verbosity.BRIEF

对于任意值,从以下开始:

public static Verbosity findByAbbr(String abbr){
for(Verbosity v : values()){
if( v.abbr().equals(abbr)){
return v;
}
}
return null;
}

只有在分析器告诉您的情况下,才能稍后继续映射实现。

我知道它在所有的值上迭代,但只有3个枚举值,它几乎不值得任何其他努力,事实上,除非你有很多值,否则我不会为映射而烦恼,它会足够快。

@Lyle的回答是相当危险的,我已经看到它不起作用,特别是如果你让枚举成为一个静态的内部类。相反,我使用了类似这样的东西,它将在枚举之前加载BootstrapSingleton映射。

编辑对于现代JVM(JVM1.6或更高版本),这应该不再是一个问题,但我确实认为JRebel仍然存在问题,但我还没有机会重新测试它。

先加载我:

   public final class BootstrapSingleton {


// Reverse-lookup map for getting a day from an abbreviation
public static final Map<String, Day> lookup = new HashMap<String, Day>();
}

现在将其加载到枚举构造函数中:

   public enum Day {
MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;


private final String abbreviation;


private Day(String abbreviation) {
this.abbreviation = abbreviation;
BootstrapSingleton.lookup.put(abbreviation, this);
}


public String getAbbreviation() {
return abbreviation;
}


public static Day get(String abbreviation) {
return lookup.get(abbreviation);
}
}

如果你有一个内部枚举,你可以在枚举定义上面定义映射,并且(理论上)应该在之前加载。

也许,看看这个。这对我很有用。 这样做的目的是使用“/红色_颜色”查找“红色”。 如果enum很多,则将_ABC_声明为0并将enum仅加载到其中一次将带来一些性能优势。

public class Mapper {


public enum Maps {


COLOR_RED("/red_color", "RED");


private final String code;
private final String description;
private static Map<String, String> mMap;


private Maps(String code, String description) {
this.code = code;
this.description = description;
}


public String getCode() {
return name();
}


public String getDescription() {
return description;
}


public String getName() {
return name();
}


public static String getColorName(String uri) {
if (mMap == null) {
initializeMapping();
}
if (mMap.containsKey(uri)) {
return mMap.get(uri);
}
return null;
}


private static void initializeMapping() {
mMap = new HashMap<String, String>();
for (Maps s : Maps.values()) {
mMap.put(s.code, s.description);
}
}
}
}

请发表你的意见。

您可以按照Gareth Davis&;的建议使用Enum::valueOf()函数。BradMace,但请确保处理IllegalArgumentException,如果所使用的字符串不在枚举中,则会引发该错误。

您可以将枚举定义为以下代码:

public enum Verbosity
{
BRIEF, NORMAL, FULL, ACTION_NOT_VALID;
private int value;


public int getValue()
{
return this.value;
}


public static final Verbosity getVerbosityByValue(int value)
{
for(Verbosity verbosity : Verbosity.values())
{
if(verbosity.getValue() == value)
return verbosity ;
}


return ACTION_NOT_VALID;
}


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

有关更多说明,请参阅以下链接

使用Java 8,您可以通过以下方式实现:

public static Verbosity findByAbbr(final String abbr){
return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}

为了帮助其他人,我更喜欢的选项(此处未列出)使用Guava的地图功能

public enum Vebosity {
BRIEF("BRIEF"),
NORMAL("NORMAL"),
FULL("FULL");


private String value;
private Verbosity(final String value) {
this.value = value;
}


public String getValue() {
return this.value;
}


private static ImmutableMap<String, Verbosity> reverseLookup =
Maps.uniqueIndex(Arrays.asList(Verbosity.values()), Verbosity::getValue);


public static Verbosity fromString(final String id) {
return reverseLookup.getOrDefault(id, NORMAL);
}
}

在默认情况下,您可以使用null,您可以throw IllegalArgumentException,或者您的fromString可以返回Optional,无论您喜欢什么行为。

从Java8开始,您可以在单行中初始化映射,并且不需要静态块

private static Map<String, Verbosity> stringMap = Arrays.stream(values())
.collect(Collectors.toMap(Enum::toString, Function.identity()));

如果您想要一个默认值,并且不想构建查找映射,您可以创建一个静态方法来处理它。 此示例还处理预期名称以数字开头的查找。

    public static final Verbosity lookup(String name) {
return lookup(name, null);
}


public static final Verbosity lookup(String name, Verbosity dflt) {
if (StringUtils.isBlank(name)) {
return dflt;
}
if (name.matches("^\\d.*")) {
name = "_"+name;
}
try {
return Verbosity.valueOf(name);
} catch (IllegalArgumentException e) {
return dflt;
}
}

如果您需要在第二个值上使用它,您只需像在其他一些答案中一样,首先构建查找映射。

public enum EnumRole {


ROLE_ANONYMOUS_USER_ROLE ("anonymous user role"),
ROLE_INTERNAL ("internal role");


private String roleName;


public String getRoleName() {
return roleName;
}


EnumRole(String roleName) {
this.roleName = roleName;
}


public static final EnumRole getByValue(String value){
return Arrays.stream(EnumRole.values()).filter(enumRole -> enumRole.roleName.equals(value)).findFirst().orElse(ROLE_ANONYMOUS_USER_ROLE);
}


public static void main(String[] args) {
System.out.println(getByValue("internal role").roleName);
}

}