How can I lookup a Java enum from its String value?

Viewed 323396

I would like to lookup an enum from its string value (or possibly any other value). I've tried the following code but it doesn't allow static in initialisers. Is there a simple way?

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);
    }
};
12 Answers

Use the valueOf method which is automatically created for each Enum.

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

For arbitrary values start with:

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

Only move on later to Map implementation if your profiler tells you to.

I know it's iterating over all the values, but with only 3 enum values it's hardly worth any other effort, in fact unless you have a lot of values I wouldn't bother with a Map it'll be fast enough.

You're close. For arbitrary values, try something like the following:

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

And you can't use valueOf()?

Edit: Btw, there is nothing stopping you from using static { } in an enum.

In case it helps others, the option I prefer, which is not listed here, uses Guava's Maps functionality:

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

With the default you can use null, you can throw IllegalArgumentException or your fromString could return an Optional, whatever behavior you prefer.

since java 8 you can initialize the map in a single line and without static block

private static Map<String, Verbosity> stringMap = Arrays.stream(values())
                 .collect(Collectors.toMap(Enum::toString, Function.identity()));
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);
}

}

If you want a default value and don't want to build lookup maps, you can create a static method to handle that. This example also handles lookups where the expected name would start with a number.

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

If you need it on a secondary value, you would just build the lookup map first like in some of the other answers.

You can define your Enum as following code :

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

See following link for more clarification

Related