Как я могу найти перечисление 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);
}
};
10 ответов
Использовать valueOf
метод, который автоматически создается для каждого Enum.
Verbosity.valueOf("BRIEF") == Verbosity.BRIEF
Для произвольных значений начните с:
public static Verbosity findByAbbr(String abbr){
for(Verbosity v : values()){
if( v.abbr().equals(abbr)){
return v;
}
}
return null;
}
Перейдите к реализации Map только позже, если ваш профилировщик скажет вам об этом.
Я знаю, что он перебирает все значения, но с только тремя значениями enum вряд ли стоит каких-либо других усилий, на самом деле, если у вас нет много значений, я бы не стал возиться с Map, это будет достаточно быстро.
Ты рядом. Для произвольных значений попробуйте что-то вроде следующего:
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);
}
}
С Java 8 вы можете достичь с помощью этого способа:
public static Verbosity findByAbbr(final String abbr){
return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}
@ Ответ Лайла довольно опасен, и я видел, что он не работает, особенно если сделать enum статическим внутренним классом. Вместо этого я использовал что-то вроде этого, которое будет загружать карты BootstrapSingleton до перечисления.
Редактировать это больше не должно быть проблемой с современными JVM (JVM 1.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>();
}
Теперь загрузите его в конструктор enum:
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);
}
}
Если у вас есть внутреннее перечисление, вы можете просто определить карту над определением перечисления, и это (теоретически) должно быть загружено раньше.
И вы не можете использовать valueOf ()?
Редактировать: Кстати, ничто не мешает вам использовать static { } в перечислении.
Начиная с Java 8 вы можете инициализировать карту в одну строку и без статического блока
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);
}
}
В случае, если это помогает другим, предпочтительный вариант, которого здесь нет в списке, использует функциональность карт 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
Какое бы поведение вы ни предпочли.
В спецификации языка Java 7 есть пример! это отражает ваш вопрос об инициализации карты с помощью собственных ссылок.
Возможно, взгляните на это. Это работает для меня. Целью этого является поиск "RED" с "/red_color". Объявление static map
и загрузка enum
только один раз принесет некоторые преимущества в производительности, если 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);
}
}
}
}
Пожалуйста, оставьте свой отзыв.
Если вы хотите использовать значение по умолчанию и не хотите строить карты поиска, вы можете создать статический метод для его обработки. В этом примере также обрабатываются поисковые запросы, в которых ожидаемое имя начинается с числа.
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;
}
}
Если вам это нужно для вторичного значения, вы просто сначала создаете карту поиска, как в некоторых других ответах.
Вы можете определить свой Enum как следующий код:
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();
}
};
Смотрите следующую ссылку для получения дополнительной информации
Вы можете использовать Enum::valueOf()
функции, как предложено Гарет Дэвис и Брэд Мейс выше, но убедитесь, что вы обрабатываете IllegalArgumentException
это было бы брошено, если используемая строка не присутствует в перечислении.