values - java enum用法




通過字符串值查找Java枚舉 (16)

Apache的commons-lang庫有一個靜態函數org.apache.commons.lang3.EnumUtils.getEnum ,它將把一個String映射到你的Enum類型。 與Geoffreys基本相同,但為什麼在野外已經有了自己的產品呢?

假設我有一個枚舉

public enum Blah {
    A, B, C, D
}

我想找到一個字符串的枚舉值,例如"A" ,它將是Blah.A 怎麼可能做到這一點?

Enum.valueOf()是我需要的方法嗎? 如果是這樣,我將如何使用它?


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;
        }

}

下面是我使用的一個漂亮的實用程序:

/**
 * 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 for Enum.valueOf作為T被刪除。


你也應該小心你的情況。 讓我解釋一下:做Blah.valueOf("A")作品,但Blah.valueOf("a")不起作用。 然後再Blah.valueOf("a".toUpperCase(Locale.ENGLISH))將工作。

編輯
基於tc更改為toUpperCase(Locale.ENGLISH) 。 評論和Java文檔

edit2在android上,你應該使用Locale.US ,就像sulai指出的那樣


使用Blah.valueOf(string)是最好的,但你也可以使用Enum.valueOf(Blah.class, string)


使用來自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);
  }
}

另請參閱:

Oracle Java示例使用Enum和Map實例

靜態塊在Enum類型中的執行順序

我如何從其String值查找Java枚舉


另一個實用程序捕獲的方式相反 使用一個標識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中唯一的public,不是最終的,也不是static方法。 如果Foo比公有的多,而不是最終的而非靜態方法,例如getTranslate返回“drei”,則可以使用另一個方法: EnumUtil.from(Foo.class, "drei", "getTranslate")


在Java 8中,靜態的Map模式更容易,是我的優先方法。 如果你想用Jackson的Enum,你可以重寫toString並使用它來代替name,然後用@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);
    }
}

如果你不想編寫自己的工具,請使用Google的guava圖書館:

Enums.getIfPresent(Blah.class, "A")

與內置的java函數不同,它讓你檢查A是否存在於Blah中,並且不會拋出異常。


如果文本與枚舉值不相同,則為另一種解決方案:

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;
  }
}

我的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語言本身中獲得一些好處; 例如:

  1. 在HeaderParam註解中直接轉換類型

是的, Blah.valueOf("A")會給你Blah.A

請注意,名稱必須完全匹配,包括case: Blah.valueOf("a")Blah.valueOf("A ")都會拋出IllegalArgumentException

靜態方法valueOf()values()是在編譯時創建的,並不出現在源代碼中。 儘管如此,它們確實出現在Javadoc中; 例如, Dialog.ModalityType顯示兩種方法。


為了增加以前的答案,並解決一些關於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();
        }
    }
}

對於那些不知道的,這裡有一些關於避免null與可選的更多信息: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional : https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional


這裡有一個方法可以處理任何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()
    ));
}

關於什麼?

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;
}




enums