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

JavaEnumsLookup

Java Problem Overview


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

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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

Solution 3 - Java

with Java 8 you can achieve with this way:

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

Solution 4 - Java

@Lyle's answer is rather dangerous and I have seen it not work particularly if you make the enum a static inner class. Instead I have used something like this which will load the BootstrapSingleton maps before the enums.

Edit this should not be a problem any more with modern JVMs (JVM 1.6 or greater) but I do think there are still issues with JRebel but I haven't had a chance to retest it.

Load me first:

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

Now load it in the enum constructor:

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

If you have an inner enum you can just define the Map above the enum definition and that (in theory) should get loaded before.

Solution 5 - Java

And you can't use valueOf()?

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

Solution 6 - Java

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.

Solution 7 - Java

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

Solution 8 - Java

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

}

Solution 9 - Java

Perhaps, take a look at this. Its working for me. The purpose of this is to lookup 'RED' with '/red_color'. Declaring a static map and loading the enums into it only once would bring some performance benefits if the enums are many.

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

Please put in your opinons.

Solution 10 - Java

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.

Solution 11 - Java

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

Solution 12 - Java

You can use the Enum::valueOf() function as suggested by Gareth Davis & Brad Mace above, but make sure you handle the IllegalArgumentException that would be thrown if the string used is not present in the enum.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpeter.murray.rustView Question on Stackoverflow
Solution 1 - JavaGareth DavisView Answer on Stackoverflow
Solution 2 - JavaLyleView Answer on Stackoverflow
Solution 3 - JavaLam LeView Answer on Stackoverflow
Solution 4 - JavaAdam GentView Answer on Stackoverflow
Solution 5 - JavaFredrikView Answer on Stackoverflow
Solution 6 - JavaChad BefusView Answer on Stackoverflow
Solution 7 - JavaAdrianView Answer on Stackoverflow
Solution 8 - JavaVahap GencdalView Answer on Stackoverflow
Solution 9 - JavaMidhunView Answer on Stackoverflow
Solution 10 - JavaScrappyDevView Answer on Stackoverflow
Solution 11 - JavaVinay SharmaView Answer on Stackoverflow
Solution 12 - JavaMayank ButporiView Answer on Stackoverflow