초기 - java enum 활용
Java에서 문자열 값에서 열거 형 값을 가져 오는 방법은 무엇입니까? (16)
그냥 enum이 있다고 해봅시다.
public enum Blah {
A, B, C, D
}
문자열의 enum 값을 찾고 싶습니다. 예를 들어 "A"
는 Blah.A
입니다. 이것을 어떻게 할 수 있습니까?
Enum.valueOf()
메서드가 필요한 것입니까? 그렇다면 어떻게 사용합니까?
Enum의 암시 적 정적 메서드 name()
을 사용하여이 작업을 수행하는 또 다른 방법입니다. name은 제공된 문자열을 검사하는 데 사용할 수있는 enum을 생성하는 데 사용 된 정확한 문자열을 반환합니다.
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
영감 : 자바에서 열거 형의 예
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);
}
}
Joshua Bloch, Effective 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);
}
}
참조 :
O (1) 메소드는 해시 맵 (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;
}
}
내 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 언어 자체에서 얻는 이점을 얻을 수 있습니다. 예 :
다른 유틸리티는 역순으로 캡처합니다. 열거 형을 식별하는 값을 사용합니다. 열거 형의 이름이 아닙니다.
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")
은 getValue
를 사용하여 "drei"와 일치하게하므로 Foo.THREE
반환합니다. Foo가 "drei"를 반환하는 getTranslate
와 같이 public이 아닌 final 메소드가 아닌 경우, EnumUtil.from(Foo.class, "drei", "getTranslate")
과 같은 다른 메소드를 사용할 수 있습니다.
다음은 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()
));
}
다음은 내가 사용하는 멋진 유틸리티입니다.
/**
* 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
가 Enum.valueOf
따라 T.class
에 Enum.valueOf
를 사용할 수 없다.
아파치의 commons-lang 라이브러리는 String을 Enum 타입으로 매핑 할 정적 함수 org.apache.commons.lang3.EnumUtils.getEnum 가지고 있습니다. 본질적으로 Geoffreys와 같은 대답이지만, 이미 야생에있을 때 왜 자신의 것을 굴려 놓을까요?
예, Blah.valueOf("A")
가 당신에게 Blah.A
를 줄 것 Blah.A
.
대 / 소문자를 포함하여 이름은 정확히 일치해야합니다. Blah.valueOf("a")
및 Blah.valueOf("A ")
모두 IllegalArgumentException
시킵니다.
정적 메소드 인 valueOf()
와 values()
는 컴파일시 생성되며 소스 코드에는 나타나지 않습니다. 그들은 Javadoc에 나타납니다. 예를 들어 Dialog.ModalityType
은 두 가지 방법을 모두 보여줍니다.
이건 어떤가요?
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();
}
}
}
이전 답변에 추가하고 nulls 및 NPE 관련 토론의 일부를 해결하려면 부재 / 잘못된 사례를 처리하기 위해 Guava Optionals를 사용하고 있습니다. 이것은 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();
}
}
}
알지 못하는 사람들을 위해 여기에 Optional을 사용하여 null을 피하는 방법에 대한 자세한 정보가 있습니다. https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
텍스트가 열거 형 값과 다른 경우 다른 해결책은 다음과 같습니다.
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;
}
}
필자는 이러한 종류의 프로세스를 사용하여 문자열로 명령을 열거 형으로 구문 분석합니다. 나는 일반적으로 열거 형 중 하나를 "알 수 없음"으로 사용하므로 null이 아닌 (값이 없음을 의미하는) 다른 것 (대소 문자를 구별하지 않는 경우에도)이 발견되지 않을 때 반환하는 데 도움이됩니다. 그러므로 나는이 접근법을 사용한다.
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;
}
java.lang.Enum
은 Java의 모든 열거 형에서 사용할 수있는 몇 가지 유용한 메서드 java.lang.Enum
정의합니다.
-
name()
메서드를 사용하여 열거 형 상수의 이름을 가져올 수 있습니다. 열거 형 상수를 쓰는 데 사용되는 문자열 리터럴은 해당 이름입니다. - 마찬가지로
values()
메서드를 사용하여 열거 형에서 모든 열거 형 상수의 배열을 가져올 수 있습니다. - 그리고 질문에 대해서는 아래와 같이
valueOf()
메서드를 사용하여 String을 Java의 Enum 상수로 변환 할 수 있습니다.
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()
메서드는 "MALE"
을 반환하는 이름을 호출하는 Enum 상수 Gender.MALE을 반환합니다.
switch
이 아직 언급되지 않았기 때문에 (OP의 enum을 재사용) 그것을 소개합니다.
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)
, null
는 돌려 Enum.valueOf(String name)
지지 않는 형태로 IllegalArgumentException
하지 않고, Enum.valueOf(String name)
의 contract 을 유지합니다. 따라서 이름이 null
이고 defaultValue
가 null
경우 default
경우 NullPointerException
을 던집니다. 그것이 valueOfOrDefault
작동하는 방식입니다.
이 접근법은 Java 8에서 Map.getOrDefault(Object key, V defaultValue)
메소드를 제공하는 Map
Map.getOrDefault(Object key, V defaultValue)
의 설계를 채택합니다.