There are several different ways to approach solving the problem of finding a specific enum instances by name while ignoring case sensitivity. The solutions are listed in order of simplicity.
- An immediate local solution iterating over the name space (inefficient)
- A generic global solution iterating over the name space (inefficient)
- A pattern to cache enhance a specific enum (efficient)
- A generic pattern to cache all enums (efficient)
Given the following enum definition...
public enum EnumExample {
AUTH_SLOTH,
FUNKY_MONKEY,
WIMP_CHIMP;
}
Solution 1:
Inspired by this solution, it has been reified into a pair of public static
methods to encourage DRY (Don't Repeat Yourself, i.e. copy pasta code duplication). To meet a one-off need, there's nothing stopping its being used directly, forgoing the formality of creating methods.
public static EnumExample valueOfIgnoreCaseDefaultToFirstListed(String name)
return valueOfIgnoreCase(name, EnumExample.values()[0]);
public static EnumExample valueOfIgnoreCase(String name, EnumExample orElseDefault) {
return Arrays.stream(EnumExample.values())
.filter(enumExample -> enumExample.name().equalsIgnoreCase(name))
.findAny()
.orElse(orElseDefault);
System.out.println(valueOfIgnoreCaseDefaultToFirstListed("funky_MONkey"));
//Found and prints FUNKY_MONKEY
System.out.println(valueOfIgnoreCaseDefaultToFirstListed("aUtH_sloth"));
//Found and prints AUTH_SLOTH
System.out.println(valueOfIgnoreCaseDefaultToFirstListed("grape_APE"));
//Not found, and prints default AUTH_SLOTH (which is the first listed)
System.out.println(valueOfIgnoreCase("funky_MONkey", EnumExample.WIMP_CHIMP));
//Found and prints FUNKY_MONKEY
System.out.println(valueOfIgnoreCase("grape_APE", EnumExample.WIMP_CHIMP));
//Not found and prints WIMP_CHIMP
System.out.println(valueOfIgnoreCase("grape_APE", null));
//Not found and prints null
Solution 2:
Inspired by this solution, it has also been reified into a pair of generic public static
methods to encourage DRY. It is also recommended this be placed in a catch-all utilities class, if the intention is to use it globally across one's project(s).
public static <T extends Enum<?>> T valueOfIgnoreCaseDefaultToFirstListed(Class<T> classEnumT,
String name)
return valueOfIgnoreCase(classEnumT, name, classEnumT.getEnumConstants()[0]);
public static <T extends Enum<?>> T valueOfIgnoreCase(Class<T> classEnumT,
String name, T orElseDefault)
return Arrays.stream(classEnumT.getEnumConstants())
.filter(enumTConstant -> enumTConstant.name().equalsIgnoreCase(name))
.findAny()
.orElse(orElseDefault);
System.out.println(valueOfIgnoreCaseDefaultToFirstListed(EnumExample.class, "funky_MONkey"));
//Found and prints FUNKY_MONKEY
System.out.println(valueOfIgnoreCaseDefaultToFirstListed(EnumExample.class, "aUtH_sloth"));
//Found and prints AUTH_SLOTH
System.out.println(valueOfIgnoreCaseDefaultToFirstListed(EnumExample.class, "grape_APE"));
//Not found, and prints default AUTH_SLOTH (which is the first listed)
System.out.println(valueOfIgnoreCase(EnumExample.class, "funky_MONkey", EnumExample.WIMP_CHIMP));
//Found and prints FUNKY_MONKEY
System.out.println(valueOfIgnoreCase(EnumExample.class, "grape_APE", EnumExample.WIMP_CHIMP));
//Not found and prints WIMP_CHIMP
System.out.println(valueOfIgnoreCase(EnumExample.class, "grape_APE", null));
//Not found and prints null
Solution 3:
If the function is going to be used at scale, then it is worth considering investing the effort into implementing a caching pattern directly within the enum
itself.
public enum EnumExample {
AUTH_SLOTH,
FUNKY_MONKEY,
WIMP_CHIMP;
final private static Map<String, EnumExample> BY_NAME_LOWER_CASE =
Arrays.stream(EnumExample.values())
.collect(
Collectors
.toMap(enumExample -> enumExample.name().toLowerCase(), Function.identity()));
public static EnumExample valueOfIgnoreCaseDefaultToFirstListed(String name)
return valueOfIgnoreCase(name, EnumExample.values()[0]);
public static EnumExample valueOfIgnoreCase(String name, EnumExample orElseDefault)
var result = BY_NAME_LOWER_CASE.get(name.toLowerCase());
return (result != null)
? result
: orElseDefault;
}
System.out.println(EnumExample.valueOfIgnoreCaseDefaultToFirstListed("funky_MONkey"));
//Found and prints FUNKY_MONKEY
System.out.println(EnumExample.valueOfIgnoreCaseDefaultToFirstListed("aUtH_sloth"));
//Found and prints AUTH_SLOTH
System.out.println(EnumExample.valueOfIgnoreCaseDefaultToFirstListed("grape_APE"));
//Not found, and prints default AUTH_SLOTH (which is the first listed)
System.out.println(EnumExample.valueOfIgnoreCase("funky_MONkey", EnumExample.WIMP_CHIMP));
//Found and prints FUNKY_MONKEY
System.out.println(EnumExample.valueOfIgnoreCase("grape_APE", EnumExample.WIMP_CHIMP));
//Not found and prints WIMP_CHIMP
System.out.println(EnumExample.valueOfIgnoreCase("grape_APE", null));
//Not found and prints null
Solution 4:
If one is working with a larger quantity of enum
s across a larger code base, the pattern described in Solution 3 will likely result in significant boilerplate.
By combining the basic generic pattern from Solution 2 with the creation of a single global place to lazily cache the entire code base's enum
s, DRY is maximized while the boilerplate (anti-DRY) of Solution 3 has been significantly reduced.
private static final Map<Class<?>, Map<String, ?>> ENUM_INSTANCE_BY_NAME_LOWERCASE_BY_ENUMCLASS = new HashMap<>();
private static <T extends Enum<T>> Map<String, T> fetchCachedEnumInstanceByNameLowerCase(Class<T> classEnumT) {
Map<String, T> result = null;
var enumInstanceByNameLowerCase = ENUM_INSTANCE_BY_NAME_LOWERCASE_BY_ENUMCLASS.get(classEnumT);
if (enumInstanceByNameLowerCase != null) {
//noinspection unchecked
result = (Map<String, T>)enumInstanceByNameLowerCase;
} else {
var tsByNameLowerCase =
Arrays.stream(classEnumT.getEnumConstants())
.collect(
Collectors
.toMap(enumTConstant -> enumTConstant.name().toLowerCase(), Function.identity()));
ENUM_INSTANCE_BY_NAME_LOWERCASE_BY_ENUMCLASS.put(classEnumT, tsByNameLowerCase);
result = tsByNameLowerCase;
}
return result;
}
public static <T extends Enum<T>> T ValueOfIgnoreCaseDefaultToFirstListed(Class<T> classEnumT,
String search)
return (classEnumT != null)
? valueOfIgnoreCase(classEnumT, search, classEnumT.getEnumConstants()[0])
: null;
public static <T extends Enum<T>> T valueOfIgnoreCase(Class<T> classEnumT,
String search, T orElseDefault)
return (classEnumT != null)
? fetchCachedEnumInstanceByNameLowerCase(classEnumT)
.getOrDefault(search.toLowerCase(), orElseDefault)
: null;
System.out.println(staticGenericCachedValueOfIgnoreCaseDefaultToFirstListed(EnumExample.class, "funky_MONkey"));
//Found and prints FUNKY_MONKEY
System.out.println(staticGenericCachedValueOfIgnoreCaseDefaultToFirstListed(EnumExample.class, "aUtH_sloth"));
//Found and prints AUTH_SLOTH
System.out.println(staticGenericCachedValueOfIgnoreCaseDefaultToFirstListed(EnumExample.class, "grape_APE"));
//Not found, and prints default AUTH_SLOTH (which is the first listed)
System.out.println(staticGenericCachedValueOfIgnoreCase(EnumExample.class, "funky_MONkey", EnumExample.WIMP_CHIMP));
//Found and prints FUNKY_MONKEY
System.out.println(staticGenericCachedValueOfIgnoreCase(EnumExample.class, "grape_APE", EnumExample.WIMP_CHIMP));
//Not found and prints WIMP_CHIMP
System.out.println(staticGenericCachedValueOfIgnoreCase(EnumExample.class, "grape_APE", null));
//Not found and prints null