Как получить значение перечисления из строкового значения в Java?
Скажем, у меня есть перечисление, которое просто
public enum Blah {
A, B, C, D
}
и я хотел бы найти значение перечисления строки, например "A"
который был бы Blah.A
, Как можно было бы сделать это?
Это Enum.valueOf()
метод мне нужен? Если так, как бы я использовал это?
33 ответа
Да, Blah.valueOf("A")
дам тебе Blah.A
,
Обратите внимание, что имя должно быть точным, включая регистр: Blah.valueOf("a")
а также Blah.valueOf("A ")
оба бросают IllegalArgumentException
,
Статические методы valueOf()
а также values()
создаются во время компиляции и не появляются в исходном коде. Они появляются в Javadoc, хотя; например, Dialog.ModalityType
показывает оба метода.
Другое решение, если текст не совпадает со значением перечисления:
public enum Blah {
A("text1"),
B("text2"),
C("text3"),
D("text4");
private String text;
Blah(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
public static Blah fromString(String text) {
for (Blah b : Blah.values()) {
if (b.text.equalsIgnoreCase(text)) {
return b;
}
}
return null;
}
}
Используйте образец из Джошуа Блоха, Эффективная Java:
(упрощено для краткости)
enum MyEnum {
ENUM_1("A"),
ENUM_2("B");
private String name;
private static final Map<String,MyEnum> ENUM_MAP;
MyEnum (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
// Build an immutable map of String name to enum pairs.
// Any Map impl can be used.
static {
Map<String,MyEnum> map = new ConcurrentHashMap<String,MyEnum>();
for (MyEnum instance : MyEnum.values()) {
map.put(instance.getName(),instance);
}
ENUM_MAP = Collections.unmodifiableMap(map);
}
public static MyEnum get (String name) {
return ENUM_MAP.get(name);
}
}
Также см:
Пример Oracle Java с использованием Enum и Map of instance
Вот изящная утилита, которую я использую:
/**
* A common method for all enums since they can't have another base class
* @param <T> Enum type
* @param c enum type. All enums must be all caps.
* @param string case insensitive
* @return corresponding enum, or null
*/
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string) {
if( c != null && string != null ) {
try {
return Enum.valueOf(c, string.trim().toUpperCase());
} catch(IllegalArgumentException ex) {
}
}
return null;
}
Затем в моем классе enum я обычно сохраняю набор текста:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Если ваши перечисления не все заглавные, просто измените Enum.valueOf
линия.
Жаль, что я не могу использовать T.class
за Enum.valueOf
как T
стерта.
Вы также должны быть осторожны с вашим делом. Позвольте мне объяснить: делать Blah.valueOf("A")
работает, но Blah.valueOf("a")
не будет работать. Тогда снова Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
должно сработать.
редактировать
Изменено toUpperCase
в toUpperCase(Locale.ENGLISH)
на основании тс. комментарий и документы по Java
edit2 на андроид вы должны использовать Locale.US
, как указывает Сулай.
В Java 8 или более поздней версии, используя Streams:
public enum Blah
{
A("text1"),
B("text2"),
C("text3"),
D("text4");
private String text;
Blah(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
public static Blah fromText(String text) {
return Arrays.stream(values())
.filter(bl -> bl.text.equalsIgnoreCase(text))
.findFirst()
.orElse(null);
}
}
Вот метод, который может сделать это для любого Enum и нечувствителен к регистру.
/**
* Finds the value of the given enumeration by name, case-insensitive.
* Throws an IllegalArgumentException if no match is found.
**/
public static <T extends Enum<T>> T valueOfIgnoreCase(
Class<T> enumeration, String name) {
for (T enumValue : enumeration.getEnumConstants()) {
if (enumValue.name().equalsIgnoreCase(name)) {
return enumValue;
}
}
throw new IllegalArgumentException(String.format(
"There is no value with name '%s' in Enum %s",
name, enumeration.getName()
));
}
Мои 2 цента здесь: использование потоков Java8 + проверка точной строки:
public enum MyEnum {
VALUE_1("Super"),
VALUE_2("Rainbow"),
VALUE_3("Dash"),
VALUE_3("Rocks");
private final String value;
MyEnum(String value) {
this.value = value;
}
/**
* @return the Enum representation for the given string.
* @throws IllegalArgumentException if unknown string.
*/
public static MyEnum fromString(String s) throws IllegalArgumentException {
return Arrays.stream(MyEnum.values())
.filter(v -> v.value.equals(s))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("unknown value: " + s));
}
}
** РЕДАКТИРОВАТЬ **
Переименовал функцию в fromString()
так как присвоение ему имени в соответствии с этим соглашением, вы получите некоторые преимущества от самого языка Java; например:
С помощью Blah.valueOf(string)
лучше, но вы можете использовать Enum.valueOf(Blah.class, string)
также.
Если вы не хотите писать свою собственную утилиту, используйте библиотеку Google guava:
Enums.getIfPresent(Blah.class, "A")
В отличие от встроенной функции Java, она позволяет вам проверить, присутствует ли A в Blah и не выдает ли исключение.
Вам может понадобиться это:
public enum ObjectType {
PERSON("Person");
public String parameterName;
ObjectType(String parameterName) {
this.parameterName = parameterName;
}
public String getParameterName() {
return this.parameterName;
}
//From String method will return you the Enum for the provided input string
public static ObjectType fromString(String parameterName) {
if (parameterName != null) {
for (ObjectType objType : ObjectType.values()) {
if (parameterName.equalsIgnoreCase(objType.parameterName)) {
return objType;
}
}
}
return null;
}
}
Еще одно дополнение:
public static String fromEnumName(String parameterName) {
if (parameterName != null) {
for (DQJ objType : DQJ.values()) {
if (parameterName.equalsIgnoreCase(objType.name())) {
return objType.parameterName;
}
}
}
return null;
}
Это вернет вам значение по строковому имени Enum. Например, если вы укажете "PERSON" в fromEnumName, он вернет вам значение Enum, то есть "Person"
Еще один способ сделать это с помощью неявного статического метода name()
Enum. name возвращает точную строку, использованную для создания этого перечисления, которое можно использовать для проверки по предоставленной строке:
public enum Blah {
A, B, C, D;
public static Blah getEnum(String s){
if(A.name().equals(s)){
return A;
}else if(B.name().equals(s)){
return B;
}else if(C.name().equals(s)){
return C;
}else if (D.name().equals(s)){
return D;
}
throw new IllegalArgumentException("No Enum specified for this string");
}
}
Тестирование:
System.out.println(Blah.getEnum("B").name());
//it will print B B
вдохновение: 10 примеров Enum на Java
В Java 8 шаблон статической карты еще проще и является моим предпочтительным методом. Если вы хотите использовать Enum с Джексоном, вы можете переопределить toString и использовать его вместо имени, а затем аннотировать @JsonValue
public enum MyEnum {
BAR,
BAZ;
private static final Map<String, MyEnum> MAP = Stream.of(MyEnum.values()).collect(Collectors.toMap(Enum::name, Function.identity()));
public static MyEnum fromName(String name){
return MAP.get(name);
}
}
public enum MyEnumForJson {
BAR("bar"),
BAZ("baz");
private static final Map<String, MyEnumForJson> MAP = Stream.of(MyEnumForJson.values()).collect(Collectors.toMap(Object::toString, Function.identity()));
private final String value;
MyEnumForJson(String value) {
this.value = value;
}
@JsonValue
@Override
public String toString() {
return value;
}
public static MyEnumForJson fromValue(String value){
return MAP.get(value);
}
}
Enum очень полезен, я использую Enum
много добавить описание для некоторых полей на разных языках, как в следующем примере:
public enum Status {
ACT(new String[] { "Accepted", "مقبول" }),
REJ(new String[] { "Rejected", "مرفوض" }),
PND(new String[] { "Pending", "في الانتظار" }),
ERR(new String[] { "Error", "خطأ" }),
SNT(new String[] { "Sent", "أرسلت" });
private String[] status;
public String getDescription(String lang) {
return lang.equals("en") ? status[0] : status[1];
}
Status(String[] status) {
this.status = status;
}
}
И затем вы можете получить описание динамически на основе кода языка, переданного в getDescription(String lang)
метод, например:
String statusDescription = Status.valueOf("ACT").getDescription("en");
Решение с использованием библиотек Guava. Метод getPlanet () нечувствителен к регистру, поэтому getPlanet ("MerCUrY") вернет Planet.MERCURY.
package com.universe.solarsystem.planets;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Enums;
import com.google.common.base.Optional;
//Pluto and Eris are dwarf planets, who cares!
public enum Planet {
MERCURY,
VENUS,
EARTH,
MARS,
JUPITER,
SATURN,
URANUS,
NEPTUNE;
public static Planet getPlanet(String name) {
String val = StringUtils.trimToEmpty(name).toUpperCase();
Optional <Planet> possible = Enums.getIfPresent(Planet.class, val);
if (!possible.isPresent()) {
throw new IllegalArgumentException(val + "? There is no such planet!");
}
return possible.get();
}
}
Библиотека Apache commons-lang имеет статическую функцию org.apache.commons.lang3.EnumUtils.getEnum, которая будет отображать строку в ваш тип Enum. Тот же ответ, что и у Джеффриса, но зачем бросать свой, когда он уже в дикой природе.
Чтобы добавить к предыдущим ответам и обсудить некоторые дискуссии вокруг нулей и NPE, я использую дополнительные возможности Guava для обработки отсутствующих / недействительных случаев. Это прекрасно работает для разбора URI/ параметров.
public enum E {
A,B,C;
public static Optional<E> fromString(String s) {
try {
return Optional.of(E.valueOf(s.toUpperCase()));
} catch (IllegalArgumentException|NullPointerException e) {
return Optional.absent();
}
}
}
Для тех, кто не знает, вот еще некоторая информация о том, как избежать нуля с помощью Необязательно: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained
O(1) метод, основанный на сгенерированном коде, который использует хэш-карту.
public enum USER {
STUDENT("jon",0),TEACHER("tom",1);
private static final Map<String, Integer> map = new HashMap<>();
static {
for (USER user : EnumSet.allOf(USER.class)) {
map.put(user.getTypeName(), user.getIndex());
}
}
public static int findIndexByTypeName(String typeName) {
return map.get(typeName);
}
private USER(String typeName,int index){
this.typeName = typeName;
this.index = index;
}
private String typeName;
private int index;
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
Как насчет?
public enum MyEnum {
FIRST,
SECOND,
THIRD;
public static Optional<MyEnum> fromString(String value){
try{
return Optional.of(MyEnum.valueOf(value));
}catch(Exception e){
return Optional.empty();
}
}
}
public static MyEnum getFromValue(String value) {
MyEnum resp = null;
MyEnum nodes[] = values();
for(int i = 0; i < nodes.length; i++) {
if(nodes[i].value.equals(value)) {
resp = nodes[i];
break;
}
}
return resp;
}
Enum valueOf() Класс перечисления автоматически получает статический метод valueOf() в классе при компиляции. Метод valueOf() можно использовать для получения экземпляра класса enum для заданного значения String. Например: -
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Strings.TWO.name());
}
enum Strings {
ONE, TWO, THREE
}}
java.lang.Enum
определяет несколько полезных методов, которые доступны для всех типов перечисления в Java:
- Ты можешь использовать
name()
метод получения имени любых констант Enum. Строковый литерал, используемый для записи констант enum, является их именем. - так же
values()
Метод может быть использован для получения массива всех констант Enum из типа Enum. - А для заданного вопроса вы можете использовать
valueOf()
метод для преобразования любой String в константу Enum в Java, как показано ниже.
public class EnumDemo06 {
public static void main(String args[]) {
Gender fromString = Gender.valueOf("MALE");
System.out.println("Gender.MALE.name() : " + fromString.name());
}
private enum Gender {
MALE, FEMALE;
}
}
Output:
Gender.MALE.name() : MALE
В этом фрагменте кода, valueOf()
метод возвращает константу Enum Gender.MALE, вызывая имя для которого возвращает "MALE"
,
Как switch
-версия еще не упоминалась, я ее представляю (повторно используя перечисление OP):
private enum Blah {
A, B, C, D;
public static Blah byName(String name) {
switch (name) {
case "A":
return A;
case "B":
return B;
case "C":
return C;
case "D":
return D;
default:
throw new IllegalArgumentException(
"No enum constant " + Blah.class.getCanonicalName() + "." + name);
}
}
}
Так как это не дает никакой дополнительной ценности valueOf(String name)
Метод, имеет смысл определить дополнительный метод, только если мы хотим иметь другое поведение. Если мы не хотим поднять IllegalArgumentException
мы можем изменить реализацию на:
private enum Blah {
A, B, C, D;
public static Blah valueOfOrDefault(String name, Blah defaultValue) {
switch (name) {
case "A":
return A;
case "B":
return B;
case "C":
return C;
case "D":
return D;
default:
if (defaultValue == null) {
throw new NullPointerException();
}
return defaultValue;
}
}
}
Предоставляя значение по умолчанию, мы сохраняем договор Enum.valueOf(String name)
не бросая IllegalArgumentException
таким образом, что ни в коем случае null
возвращается Поэтому мы бросаем NullPointerException
если имя null
и в случае default
если defaultValue
является null
, Вот как valueOfOrDefault
работает.
Этот подход принимает дизайн Map
-Интерфейс, который предоставляет метод Map.getOrDefault(Object key, V defaultValue)
с Java 8.
Добавление к ответу с самым высоким рейтингом, с полезной утилитой...
valueOf()
выдает два разных исключения в тех случаях, когда ему не нравится его ввод.
IllegalArgumentException
NullPointerExeption
Если ваши требования таковы, что у вас нет никакой гарантии, что ваша строка будет точно соответствовать значению перечисления, например, если данные строки поступают из базы данных и могут содержать старую версию перечисления, то вам нужно будет обработать эти довольно часто...
Итак, вот метод многократного использования, который я написал, который позволяет нам определить Enum по умолчанию, который будет возвращен, если передаваемая строка не совпадает.
private static <T extends Enum<T>> T valueOf( String name , T defaultVal) {
try {
return Enum.valueOf(defaultVal.getDeclaringClass() , name);
} catch (IllegalArgumentException | NullPointerException e) {
return defaultVal;
}
}
Используйте это так:
public enum MYTHINGS {
THINGONE,
THINGTWO
}
public static void main(String [] asd) {
valueOf("THINGTWO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGTWO
valueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE
}
Я искал ответ, чтобы найти имя "бла", а не его значение (не текст). на основе ответа @Manu ( Manu), я считаю этот код полезным:
public enum Blah {
A("text1"),
B("text2"),
C("text3"),
D("text4");
private String text;
Blah(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
public static Blah valueOfCode(String blahCode) throws IllegalArgumentException {
Blah blah = Arrays.stream(Blah.values())
.filter(val -> val.name().equals(blahCode))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unable to resolve blah : " + blahCode));
return blah;
}
}
public enum ToggleStatusUpdate {
OFF("off", 1),
ON("on", 2);
private final String name;
private final int position;
private ToggleStatusUpdate(String name, int position) {
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public int getPosition() {
return position;
}
public static int getPositionForName(String name) {
for(ToggleStatusUpdate toggleStatusUpdate : ToggleStatusUpdate.values()) {
if (toggleStatusUpdate.getName().equals(name)) {
return toggleStatusUpdate.getPosition();
}
}
return -1;
}
public static void main(String[] args) {
System.out.println(ToggleStatusUpdate.getPositionForName("off"));
}
}
Blah.valueOf("A")
- это утверждение, которое вы ищете, но имейте в виду, что это ЧУВСТВИТЕЛЬНО СЛУЧАЙНО, поэтому Blah.valueOf ("a") не будет работать и будет генерировать исключение.
Еще одна утилита захвата в обратном порядке. Использование значения, которое идентифицирует этот Enum, а не по его имени.
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.EnumSet;
public class EnumUtil {
/**
* Returns the <code>Enum</code> of type <code>enumType</code> whose a
* public method return value of this Enum is
* equal to <code>valor</code>.<br/>
* Such method should be unique public, not final and static method
* declared in Enum.
* In case of more than one method in match those conditions
* its first one will be chosen.
*
* @param enumType
* @param value
* @return
*/
public static <E extends Enum<E>> E from(Class<E> enumType, Object value) {
String methodName = getMethodIdentifier(enumType);
return from(enumType, value, methodName);
}
/**
* Returns the <code>Enum</code> of type <code>enumType</code> whose
* public method <code>methodName</code> return is
* equal to <code>value</code>.<br/>
*
* @param enumType
* @param value
* @param methodName
* @return
*/
public static <E extends Enum<E>> E from(Class<E> enumType, Object value, String methodName) {
EnumSet<E> enumSet = EnumSet.allOf(enumType);
for (E en : enumSet) {
try {
String invoke = enumType.getMethod(methodName).invoke(en).toString();
if (invoke.equals(value.toString())) {
return en;
}
} catch (Exception e) {
return null;
}
}
return null;
}
private static String getMethodIdentifier(Class<?> enumType) {
Method[] methods = enumType.getDeclaredMethods();
String name = null;
for (Method method : methods) {
int mod = method.getModifiers();
if (Modifier.isPublic(mod) && !Modifier.isStatic(mod) && !Modifier.isFinal(mod)) {
name = method.getName();
break;
}
}
return name;
}
}
Пример:
public enum Foo {
ONE("eins"), TWO("zwei"), THREE("drei");
private String value;
private Foo(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
EnumUtil.from(Foo.class, "drei")
возвращается Foo.THREE
, потому что он будет использовать getValue
соответствовать "drei", который является уникальным публичным, не финальным и не статическим методом в Foo. В случае, если Foo имеет более чем публичный, не финальный и не статический метод, например, getTranslate
который возвращает "drei", другой метод может быть использован: EnumUtil.from(Foo.class, "drei", "getTranslate")
,
Комбинация ответов и комментариев для Java 8 с использованием Streams. Он создает статическую карту для поиска с возможностью значения по умолчанию, чтобы предотвратить нулевые проверки.
public enum Blah {
A, B, C, D, INVALID
private static final Map<String, Blah> ENUM_MAP = Stream.of(Blah.values())
.collect(Collectors.toMap(Enum::name, Function.identity()));
public static Blah of(final String name) {
return ENUM_MAP.getOrDefault(name, INVALID);
}
}
// e.g.
Blah.of("A");
A
Blah.of("X")
INVALID
Самый быстрый способ получить имя enum - это создать карту текста и значения enum при запуске приложения и получить имя, вызвав функцию Blah.getEnumName():
public enum Blah {
A("text1"),
B("text2"),
C("text3"),
D("text4");
private String text;
private HashMap<String, String> map;
Blah(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
static{
createMapOfTextAndName();
}
public static void createMapOfTextAndName() {
map = new HashMap<String, String>();
for (Blah b : Blah.values()) {
map.put(b.getText(),b.toString());
}
}
public static String getEnumName(String text) {
return map.get(text.toLowerCase());
}
}