In Oracle JDK (tried with JDK 10.0.1) the class Class has the field enumConstantDirectory. This field is of type Map<String, T> for Class<T>. It stores the constants of an enum T by their names. After an enum class has been initialized enumConstantDirectory is still empty. On the first call of Enum.valueOf(Class<T> enumType, String name) all constants of the given enum T are stored in the enumConstantDirectory.
Since every enum class has already its own mapping we could try to utilize it instead of creating an additional local mapping for an/some/every enum/s.
I implemented first a utility class:
public class Enums {
private static final Field DIRECTORY_FIELD;
static {
try {
DIRECTORY_FIELD = Class.class.getDeclaredField("enumConstantDirectory");
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T extends Enum<T>> T valueOfOrDefault(Class<T> enumType, String name, T defaultValue) throws Exception {
return getEnumConstantDirectory(enumType).getOrDefault(name, defaultValue);
}
public static <T extends Enum<T>> boolean hasValueFor(Class<T> enumType, String name) throws Exception {
Map<String, T> enumConstantDirectory = getEnumConstantDirectory(enumType);
return enumConstantDirectory.containsKey(name);
}
private static <T extends Enum<T>> Map<String, T> getEnumConstantDirectory(Class<T> enumType) throws Exception {
try {
DIRECTORY_FIELD.setAccessible(true);
Map<String, T> enumConstantDirectory = (Map<String, T>) DIRECTORY_FIELD.get(enumType);
return enumConstantDirectory;
}
finally {
DIRECTORY_FIELD.setAccessible(false);
}
}
}
It can be used like this:
public enum Note {
DO, RE, MI, FA, SOL, LA, SI;
static {
Enum.valueOf(Note.class, Note.DO.name());
}
public static Note valueOfOrDefault(String name, Note defaultValue) throws Exception {
return Enums.valueOfOrDefault(Note.class, name, defaultValue);
}
public static <T extends Enum<T>> boolean hasValueFor(String name) throws Exception {
return Enums.hasValueFor(Note.class, name);
}
}
To summarize:
It's generally possible to check if a name represents an enum constant without additional maps or iterating over the enum constants. But as always with reflections there are the known drawbacks. Additionally it's required to ensure that the constants of an enum are stored in it's class.