Відповіді:
Так, Blah.valueOf("A")
дадуть тобі Blah.A
.
Зауважте, що ім'я повинно відповідати точно , включаючи регістр: Blah.valueOf("a")
і Blah.valueOf("A ")
обидва кидати IllegalArgumentException
.
Методи статичні valueOf()
і values()
створюються під час компіляції і не з'являються у вихідному коді. Вони все ж з'являються у Javadoc; наприклад, Dialog.ModalityType
показані обидва способи.
toString()
значення, ні, я б не сказав цього. name()
отримає вам фактично визначене ім’я константи перерахунку, якщо ви не перекриєте це.
enum Blah {...}
визначення не повинно намагатися оголосити своїм власним values
ні valuesOf
. Це як би ви могли писати "AnyTypeName.class", навіть якщо ви ніколи не оголошували змінну члена "class"; компілятор робить це просто Just Work. (Ця відповідь може бути вам більше не корисною через 3 місяці, але про всяк випадок.)
Ще одне рішення, якщо текст не відповідає значенню перерахування:
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;
}
}
throw new IllegalArgumentException("No constant with text " + text + " found")
було б краще, ніж return null
.
Ось чудова утиліта, яку я використовую:
/**
* 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;
}
Тоді в моєму курсі перерахування зазвичай у мене є це, щоб заощадити текст:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Якщо ваші перерахунки не всі обмежувачі, просто змініть Enum.valueOf
рядок.
Шкода , я не можу використовувати T.class
для , Enum.valueOf
як T
стирається.
Використовуйте шаблон із Джошуа Блоха, Ефективна 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
Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))
я також рекомендую переосмислити toString () (передається через конструктор) і використовувати це замість імені, особливо якщо Enum асоціюється з серіалізаційними даними, оскільки це дозволяє контролювати корпус, не даючи Sonar fit.
unmodifiableMap
, то починати з а ConcurrentHashMap
. Немає ніякої користі . Просто використовуйте HashMap
. (Якщо у вас є гуава, ImmutableMap
тоді я рекомендую це замість!)
ConcurrentHashMap
тут, де карта ніколи не змінюється після ініціалізації. Звідси навіть, наприклад, наприклад, у прикладі JLS використовується звичайний HashMap
.
Ви також повинні бути обережними зі своєю справою. Дозвольте пояснити: робіть Blah.valueOf("A")
роботи, але Blah.valueOf("a")
не вийде. Тоді знову Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
працювали б.
редагування
Змінено toUpperCase
на toUpperCase(Locale.ENGLISH)
основі tc. коментар і документи Java
edit2
На android ви повинні використовувати Locale.US
, як вказує sulai .
Locale.US
для машиночитаного вводу / виводу.
Ось метод, який може зробити це для будь-якого 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()
));
}
equalsIgnoreCase
це шлях. +1
Використання Blah.valueOf(string)
найкраще, але ви також можете використовувати Enum.valueOf(Blah.class, string)
.
У Java 8 або новіших версіях за допомогою потоків :
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 Optional<Blah> fromText(String text) {
return Arrays.stream(values())
.filter(bl -> bl.text.equalsIgnoreCase(text))
.findFirst();
}
}
Якщо ви не хочете писати власну утиліту, використовуйте Google гуава бібліотека:
Enums.getIfPresent(Blah.class, "A")
На відміну від вбудованої функції java, ми перевіримо, чи A присутній у Blah і чи не викидає це виняток.
Мої 2 центи тут: використання Java8 Streams + перевірка точного рядка:
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; наприклад:
switch
блоків, ви можете .orElse(null)
замість того, .orElseThrow()
щоб ви могли зашифрувати виняток у default
пункті - та включити більше корисної інформації, коли потрібно. І щоб зробити це більш м'яким, ви можете скористатисяv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Optional
з findFirst()
, дозволяючи користувачеві вирішити, чи хоче він .orElse(null)
, orElseThrow()
чи що завгодно ....
Вам може знадобитися це:
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;
}
Це поверне вам значення за допомогою імені Stringified Enum. Наприклад, якщо ви вкажете "PERSON" у відEEnumName, воно поверне вам значення Enum, тобто "Person"
Інший спосіб зробити це за допомогою неявного статичного методу name()
Енума. 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
valueOf
робить для вас. Цей статичний метод не пропонує нічого додаткового, винятку тощо. Тоді конструкції if / else є дуже небезпечними ... будь-яка нова додана константа перерахунку призведе до порушення цього методу без змін.
name()
не є статичним.
Рішення за допомогою бібліотек Guava. Метод getPlanet () нечутливий до регістру, тому getPlanet ("МЕРКУРІЯ") поверне Планету. МЕРКУРЮ.
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();
}
}
Щоб додати до попередніх відповідей і вирішити деякі дискусії навколо нулів та 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#Otional
У 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);
}
}
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;
}
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;
}
}
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");
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"
.
Бібліотека спільноти Apache має статичну функцію org.apache.commons.lang3.EnumUtils.getEnum, яка буде відображати рядок для вашого типу Enum. Відповідь по суті, як і Джеффріс, але навіщо катати свою, коли вона вже є в дикій природі.
Додавання відповіді до найвищої оцінки з корисною утилітою ...
valueOf()
викидає два різних винятки у випадках, коли це не сподобалось.
IllegalArgumentException
NullPointerExeption
Якщо ваші вимоги такі, що у вас немає жодної гарантії того, що ваша String обов'язково відповідатиме значення перерахунку, наприклад, якщо дані String надходять із бази даних і можуть містити стару версію enum, вам потрібно буде обробити їх часто ...
Ось ось метод, який я багаторазово використовував, який я написав, який дозволяє нам визначити 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
}
Оскільки switch
-версія ще не згадувалася, я її ввожу (повторно використовуючи перерахунок ОП):
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.
Ще одна утиліта, яка фіксує у зворотному напрямку. Використання значення, яке ідентифікує 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
який повертає «драй», інший метод може бути використаний: EnumUtil.from(Foo.class, "drei", "getTranslate")
.
Створіть розширення, а потім зателефонуйте valueOf<MyEnum>("value")
. Якщо тип недійсний, ви отримаєте null і вам доведеться його обробити
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}
Крім того, ви можете встановити значення за замовчуванням, викликаючи valueOf<MyEnum>("value", MyEnum.FALLBACK)
та уникаючи нульової відповіді. Ви можете розширити свій конкретний перелік, щоб типово було автоматичним
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
default
}
}
Або якщо ви хочете обох, зробіть друге:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Мені подобається використовувати такий процес для розбору команд як рядків у перерахуваннях. У мене зазвичай одне з перерахунків є "невідомим", тому це допомагає повернути те, що інші не знайдені (навіть у випадку нечутливості до випадків), а не нульові (це означає, що значення немає). Тому я використовую такий підхід.
static <E extends Enum<E>> Enum getEnumValue(String what, Class<E> enumClass) {
Enum<E> unknown=null;
for (Enum<E> enumVal: enumClass.getEnumConstants()) {
if (what.compareToIgnoreCase(enumVal.name()) == 0) {
return enumVal;
}
if (enumVal.name().compareToIgnoreCase("unknown") == 0) {
unknown=enumVal;
}
}
return unknown;
}
Найшвидший спосіб отримати ім'я 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.name());
}
}
public static String getEnumName(String text) {
return map.get(text.toLowerCase());
}
}
Blah.valueOf("A")
метод чутливий до регістру і не переносить сторонні пробіли, тому альтернативне рішення, запропоноване нижче @ JoséMi.