Jawaban:
Ya, Blah.valueOf("A")
akan memberimu Blah.A
.
Perhatikan bahwa nama harus sama persis , termasuk kasus: Blah.valueOf("a")
dan Blah.valueOf("A ")
keduanya melempar IllegalArgumentException
.
Metode statis valueOf()
dan values()
dibuat pada waktu kompilasi dan tidak muncul dalam kode sumber. Mereka muncul di Javadoc, meskipun; misalnya, Dialog.ModalityType
menunjukkan kedua metode.
toString()
nilainya, tidak, saya tidak akan mengatakan itu. name()
akan memberi Anda nama sebenarnya yang ditentukan dari konstanta enum kecuali Anda menimpanya.
enum Blah {...}
Definisi aktual seharusnya tidak mencoba untuk menyatakan sendiri values
atau tidak valuesOf
. Ini seperti bagaimana Anda dapat menulis "AnyTypeName.class" meskipun Anda tidak pernah benar-benar mendeklarasikan variabel anggota "kelas"; kompiler membuat semuanya Hanya Bekerja. (Jawaban ini mungkin tidak lagi berguna bagi Anda 3 bulan kemudian, tetapi untuk berjaga-jaga.)
Solusi lain jika teks tidak sama dengan nilai enumerasi:
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")
akan lebih baik daripada return null
.
Inilah utilitas bagus yang saya gunakan:
/**
* 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;
}
Kemudian di kelas enum saya, saya biasanya memiliki ini untuk menyimpan mengetik:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Jika enum Anda tidak semuanya tertutup, ubah saja Enum.valueOf
garisnya.
Sayang sekali aku tidak bisa menggunakan T.class
untuk Enum.valueOf
sebagai T
dihapus.
Gunakan pola dari Joshua Bloch, Java Efektif :
(disederhanakan untuk singkatnya)
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);
}
}
Lihat juga:
Contoh Oracle Java menggunakan Enum dan Peta instance
Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))
Saya juga merekomendasikan untuk meng-override ke Strtr () (diteruskan melalui konstruktor) dan menggunakan itu alih-alih nama, terutama jika Enum dikaitkan dengan data serial karena ini memungkinkan Anda mengontrol casing tanpa memberikan Sonar cocok.
unmodifiableMap
, tetap tidak ada manfaatnya untuk memulai dengan ConcurrentHashMap
. Cukup gunakan a HashMap
. (Jika Anda memiliki Guava ImmutableMap
maka saya akan merekomendasikan itu sebagai gantinya!)
ConcurrentHashMap
sini, di mana peta tidak pernah dimodifikasi setelah inisialisasi. Karenanya mengapa bahkan misalnya contoh dalam JLS itu sendiri menggunakan reguler HashMap
.
Anda juga harus berhati-hati dengan kasus Anda. Biarkan saya jelaskan: melakukan Blah.valueOf("A")
pekerjaan, tetapi Blah.valueOf("a")
tidak akan berhasil. Kemudian lagi Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
akan berhasil.
sunting
Diubah toUpperCase
menjadi toUpperCase(Locale.ENGLISH)
berdasarkan tc. komentar dan dokumen java
sunting2
Di android Anda harus menggunakan Locale.US
, sebagai sulai menunjukkan .
Locale.US
input / output yang dapat dibaca mesin.
Berikut adalah metode yang dapat melakukannya untuk Enum apa pun, dan tidak peka huruf besar-kecil.
/**
* 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
adalah jalan yang harus ditempuh. +1
Menggunakan Blah.valueOf(string)
itu yang terbaik tetapi Anda juga bisa menggunakannya Enum.valueOf(Blah.class, string)
.
Di Java 8 atau lebih baru, menggunakan Streaming :
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();
}
}
Jika Anda tidak ingin menulis utilitas sendiri, gunakan Google jambu biji Perpustakaan:
Enums.getIfPresent(Blah.class, "A")
Tidak seperti fungsi java yang ada di dalamnya, mari kita periksa apakah A ada dalam Blah dan tidak melempar pengecualian.
2 sen saya di sini: menggunakan Java8 Streams + memeriksa string yang tepat:
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));
}
}
** EDIT **
Berganti nama fungsinya fromString()
sejak menamainya menggunakan konvensi itu, Anda akan memperoleh beberapa manfaat dari bahasa Java itu sendiri; sebagai contoh:
switch
blok yang lebih mudah dibaca , Anda bisa .orElse(null)
sebagai ganti .orElseThrow()
sehingga Anda bisa membuat kode pengecualian lemparan dalam default
klausa - dan memasukkan info yang lebih berguna saat dibutuhkan. Dan untuk membuatnya lebih ringan Anda bisa menggunakanv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Optional
dari findFirst()
, yang memungkinkan pengguna untuk memutuskan apakah dia mau .orElse(null)
, orElseThrow()
atau apa pun ....
Anda mungkin perlu ini:
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;
}
}
Satu Tambahan Lagi:
public static String fromEnumName(String parameterName) {
if (parameterName != null) {
for (DQJ objType : DQJ.values()) {
if (parameterName.equalsIgnoreCase(objType.name())) {
return objType.parameterName;
}
}
}
return null;
}
Ini akan mengembalikan Anda Nilai oleh Nama Enum yang Dimodifikasi untuk misalnya jika Anda memberikan "PERSON" di fromEnumName, itu akan mengembalikan Anda Nilai Enum yaitu "Orang"
Cara lain untuk melakukan ini dengan menggunakan metode statis implisit name()
Enum. nama akan mengembalikan string yang tepat digunakan untuk membuat enum yang dapat digunakan untuk memeriksa terhadap string yang disediakan:
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");
}
}
Pengujian:
System.out.println(Blah.getEnum("B").name());
//it will print B B
inspirasi: 10 Contoh Enum di Jawa
valueOf
Anda lakukan. Metode statis ini tidak menawarkan tambahan apa pun, kecuali semua. Maka konstruksi if / else sangat berbahaya ... konstanta enum baru yang ditambahkan akan menyebabkan metode ini rusak tanpa perubahan.
name()
tidak statis.
Solusi menggunakan perpustakaan Guava. Metode getPlanet () bersifat case-sensitive, jadi getPlanet ("MerCUrY") akan mengembalikan 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();
}
}
Untuk menambah jawaban sebelumnya, dan membahas beberapa diskusi seputar nol dan NPE, saya menggunakan Pilihan Guava untuk menangani kasus yang tidak ada / tidak valid. Ini berfungsi baik untuk penguraian parameter / 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();
}
}
}
Bagi mereka yang tidak sadar, inilah beberapa info lebih lanjut tentang menghindari null dengan Opsional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
Di Java 8, pola Peta statis bahkan lebih mudah dan merupakan metode pilihan saya. Jika Anda ingin menggunakan Enum dengan Jackson, Anda dapat mengganti ke Strtring dan menggunakan itu alih-alih nama, lalu anotasi dengan@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) metode yang diilhami dari kode yang dihasilkan hemat yang memanfaatkan hashmap.
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 sangat berguna, saya telah menggunakan Enum
banyak untuk menambahkan deskripsi untuk beberapa bidang dalam bahasa yang berbeda, sebagai contoh berikut:
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;
}
}
Dan kemudian Anda dapat mengambil deskripsi secara dinamis berdasarkan kode bahasa yang diteruskan ke getDescription(String lang)
metode, misalnya:
String statusDescription = Status.valueOf("ACT").getDescription("en");
java.lang.Enum
mendefinisikan beberapa metode yang berguna, yang tersedia untuk semua tipe enumerasi di Jawa:
name()
metode untuk mendapatkan nama konstanta Enum. String literal yang digunakan untuk menulis konstanta enum adalah nama mereka.values()
metode dapat digunakan untuk mendapatkan array dari semua konstanta Enum dari jenis Enum.valueOf()
metode untuk mengubah sembarang String ke konstanta Enum di Jawa, seperti yang ditunjukkan di bawah ini.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
Dalam cuplikan kode ini, valueOf()
metode mengembalikan Gender.MALE konstanta Enum, memanggil nama yang mengembalikan "MALE"
.
Pustaka commons-lang Apache memiliki fungsi statis org.apache.commons.lang3.EnumUtils.getEnum yang akan memetakan sebuah String ke tipe Enum Anda. Jawaban yang sama pada dasarnya sama dengan Geoffrey tetapi mengapa menggulung sendiri saat sudah ada di luar sana.
Menambahkan ke jawaban berperingkat teratas, dengan utilitas bermanfaat ...
valueOf()
melempar dua Pengecualian berbeda dalam kasus di mana ia tidak suka inputnya.
IllegalArgumentException
NullPointerExeption
Jika persyaratan Anda sedemikian rupa sehingga Anda tidak memiliki jaminan bahwa String Anda pasti akan cocok dengan nilai enum, misalnya jika data String berasal dari database dan dapat berisi versi lama dari enum, maka Anda harus menangani ini sering...
Jadi, inilah metode yang dapat digunakan kembali yang saya tulis yang memungkinkan kita untuk mendefinisikan Enum default untuk dikembalikan jika String yang kita lewati tidak cocok.
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;
}
}
Gunakan seperti ini:
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
}
Karena versi switch
-belum disebutkan saya memperkenalkannya (menggunakan kembali enum 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);
}
}
}
Karena ini tidak memberikan nilai tambahan pada valueOf(String name)
metode, masuk akal untuk mendefinisikan metode tambahan jika kita ingin memiliki perilaku yang berbeda. Jika kami tidak ingin menaikkan, IllegalArgumentException
kami dapat mengubah implementasinya menjadi:
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;
}
}
}
Dengan memberikan nilai default, kami menjaga kontrak dari Enum.valueOf(String name)
tanpa melemparkan sebuah IllegalArgumentException
cara bahwa dalam kasus tidak null
dikembalikan. Oleh karena itu kami melempar NullPointerException
jika nama adalah null
dan default
jika defaultValue
ada null
. Begitulah cara valueOfOrDefault
kerjanya.
Pendekatan ini mengadopsi desain Map
-Interface yang menyediakan metode Map.getOrDefault(Object key, V defaultValue)
pada Java 8.
Utilitas lain menangkap dengan cara terbalik. Menggunakan nilai yang mengidentifikasi Enum itu, bukan dari namanya.
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;
}
}
Contoh:
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")
kembali Foo.THREE
, karena akan digunakan getValue
untuk mencocokkan "drei", yang merupakan publik yang unik, bukan metode final dan tidak statis di Foo. Dalam hal Foo memiliki lebih dari pada metode umum, belum final dan tidak statis, misalnya, getTranslate
yang kembali "drei", metode lainnya dapat digunakan: EnumUtil.from(Foo.class, "drei", "getTranslate")
.
Buat ekstensi lalu panggil valueOf<MyEnum>("value")
. Jika jenisnya tidak valid, Anda akan mendapatkan nol dan harus menanganinya
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}
Atau, Anda dapat menetapkan nilai default, menelepon valueOf<MyEnum>("value", MyEnum.FALLBACK)
, dan menghindari respons nol. Anda dapat memperluas enum spesifik Anda agar default menjadi otomatis
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
}
}
Atau jika Anda ingin keduanya, buat yang kedua:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Saya suka menggunakan proses semacam ini untuk mem-parsing perintah sebagai string ke enumerasi. Saya biasanya memiliki salah satu enumerasi sebagai "tidak dikenal" sehingga membantu mengembalikannya ketika yang lain tidak ditemukan (bahkan berdasarkan kasus yang tidak sensitif) daripada nol (artinya tidak ada nilai). Karenanya saya menggunakan pendekatan ini.
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;
}
Cara tercepat untuk mendapatkan nama enum adalah dengan membuat peta teks dan nilai enum saat aplikasi dimulai, dan untuk mendapatkan nama panggil fungsi 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")
metode ini case-sensitive dan tidak mentolerir ruang kosong asing, sehingga solusi alternatif yang diusulkan di bawah ini oleh @ JoséMi.