一、抽取EnumUtil的必要性

比如说,我在业务中定义了一个表示“加密类型”的枚举类 EncryptType

import cn.hutool.core.util.StrUtil;
import com.suning.tech.exception.GatewayRuntimeException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Optional;
 * 功能描述:加密类型
@AllArgsConstructor
@Getter
public enum EncryptType {
    NONE (0), // 不加密
    AES(1), // 1:aes
    RSA(2), // 2:rsa
    XXTEA(3); // 3:xxtea
    int type;
    public static EncryptType parseInt(int typeVal) {
        Optional<EncryptType> result = Arrays.stream(values()) // values() 可以获取当前枚举类所有枚举常量
            .filter(t -> t.getType() == typeVal) // 判断相等的条件
            .findFirst();
        if (result.isPresent()) {
            return result.get();
        } else {
            throw new GatewayRuntimeException(StrUtil.format("No EncryptType matches type value {}", typeVal)); // NOSONAR

这样做的好处是

  • 避免客户端代码中的魔法值;
  • 客户端代码更加清晰明了;
  • EncryptType encryptType = EncryptType.parseInt(type);
    if (EncryptType.XXTEA.equals(encryptType)) {
      // XXTEA 加密
    } else if (EncryptType.AES.equals(encryptType)) {
      // AES 加密
    } else if (EncryptType.RSA.equals(encryptType)) {
      // RSA 加密
    

    你可以想象一下,如果直接拿 int 类型的type 和 1,2,3 做比较,代码看起来会有多糟糕。

    但是,枚举类型使用得多了以后,需要在每一个枚举类中,都写一段 parseInt 类型的代码,那得多糟心!

    比如,我的项目中,就有这么多枚举类型,都需要增加解析方法!

    这不够简洁啊!!! 于是,我尝试用泛型来抽取这段方法。

    二、我的方案

    import cn.hutool.core.util.StrUtil;
    import org.springframework.util.ReflectionUtils;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    import java.util.Optional;
     * 功能描述: 枚举工具类
     * @author geekziyu
     * @version 1.0.0
    public class EnumUtil {
        public static <E extends Enum<E>> E valueOf(Class<E> e, String typeValue) {
            E[] values = e.getEnumConstants();
            Optional<E> result = Arrays.stream(values)
                    .filter(t -> String.valueOf(getTypeValue(t)).equals(typeValue)) // 用字符串形式比较
                    .findFirst();
            if (result.isPresent()) {
                return result.get();
            } else {
                throw new RuntimeException(StrUtil.format("No {} matches type value {}", e.getTypeName(), typeValue)); // NOSONAR
        public static <E extends Enum<E>> E valueOf(Class<E> e, int typeValue) {
            return valueOf(e, String.valueOf(typeValue));
        private static <E extends Enum<E>> Object getTypeValue(E e) {
            Class<? extends Enum> typeClass = e.getClass();
            try {
                Method getter = typeClass.getMethod("getTypeValue");
                ReflectionUtils.makeAccessible(getter);
                return getter.invoke(e);
            } catch (NoSuchMethodException ex) {
                throw new RuntimeException(StrUtil.format("No such method named 'getTypeValue' in Enum {}!", typeClass.getTypeName())); // NOSONAR
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(StrUtil.format("Inaccessible is the method 'getTypeValue' in Enum {} !", typeClass.getTypeName()), ex.getCause()); // NOSONAR
            } catch (InvocationTargetException ex) {
                throw new RuntimeException(StrUtil.format("Exception occurred to method 'getTypeValue' in  Enum {}!", typeClass.getTypeName()), ex.getCause()); // NOSONAR
    

    当然,我这个工具类也有局限性,那就是我限定了枚举类中,必须要有一个名为 typeValue 的字段且必须要有 getTypeValue 方法!

    三、hutool的解决方案

    public static <E extends Enum<E>> E likeValueOf(Class<E> enumClass, Object value) {
      if (value instanceof CharSequence) {
        value = value.toString().trim();
      final Field[] fields = ReflectUtil.getFields(enumClass);
      final Enum<?>[] enums = enumClass.getEnumConstants();
      String fieldName;
      for (Field field : fields) {
        fieldName = field.getName();
        if (field.getType().isEnum() || "ENUM$VALUES".equals(fieldName) || "ordinal".equals(fieldName)) {
          // 跳过一些特殊字段
          continue;
        for (Enum<?> enumObj : enums) {
          if (ObjectUtil.equal(value, ReflectUtil.getFieldValue(enumObj, field))) {
            return (E) enumObj;
      return null;
    

    EncryptType 为例,有以下字段:

    field.getType().isEnum() fieldName