Java的枚举工具类

230 阅读4分钟

枚举类型本质上也是一种类,只不过这个类的对象是有限的、固定的几个,不能让用户随意创建。

    场景:

    开发中,如果针对于某个类,它的实例的个数是确定的。则推荐将此类声明为枚举类。

    如果枚举类的实例只有一个,则可以看作是单例的实现方式。

    

枚举工具类:包含常用的枚举场景功能

public class EnumUtil {

   /**
    * 指定类是否为Enum类
    *
    * @param clazz 类
    * @return 是否为Enum类
    */
   public static boolean isEnum(Class<?> clazz) {
      Assert.notNull(clazz);
      return clazz.isEnum();
   }

   /**
    * 指定类是否为Enum类
    *
    * @param obj 类
    * @return 是否为Enum类
    */
   public static boolean isEnum(Object obj) {
      Assert.notNull(obj);
      return obj.getClass().isEnum();
   }

   /**
    * Enum对象转String,调用{@link Enum#name()} 方法
    *
    * @param e Enum
    * @return name值
    * @since 4.1.13
    */
   public static String toString(Enum<?> e) {
      return null != e ? e.name() : null;
   }

   /**
    * 获取给定位置的枚举值
    *
    * @param <E>       枚举类型泛型
    * @param enumClass 枚举类
    * @param index     枚举索引
    * @return 枚举值,null表示无此对应枚举
    * @since 5.1.6
    */
   public static <E extends Enum<E>> E getEnumAt(Class<E> enumClass, int index) {
      final E[] enumConstants = enumClass.getEnumConstants();
      return index >= 0 && index < enumConstants.length ? enumConstants[index] : null;
   }

   /**
    * 字符串转枚举,调用{@link Enum#valueOf(Class, String)}
    *
    * @param <E>       枚举类型泛型
    * @param enumClass 枚举类
    * @param value     值
    * @return 枚举值
    * @since 4.1.13
    */
   public static <E extends Enum<E>> E fromString(Class<E> enumClass, String value) {
      return Enum.valueOf(enumClass, value);
   }

   /**
    * 字符串转枚举,调用{@link Enum#valueOf(Class, String)}<br>
    * 如果无枚举值,返回默认值
    *
    * @param <E>          枚举类型泛型
    * @param enumClass    枚举类
    * @param value        值
    * @param defaultValue 无对应枚举值返回的默认值
    * @return 枚举值
    * @since 4.5.18
    */
   public static <E extends Enum<E>> E fromString(Class<E> enumClass, String value, E defaultValue) {
      return ObjectUtil.defaultIfNull(fromStringQuietly(enumClass, value), defaultValue);
   }

   /**
    * 字符串转枚举,调用{@link Enum#valueOf(Class, String)},转换失败返回{@code null} 而非报错
    *
    * @param <E>       枚举类型泛型
    * @param enumClass 枚举类
    * @param value     值
    * @return 枚举值
    * @since 4.5.18
    */
   public static <E extends Enum<E>> E fromStringQuietly(Class<E> enumClass, String value) {
      if (null == enumClass || StrUtil.isBlank(value)) {
         return null;
      }

      try {
         return fromString(enumClass, value);
      } catch (IllegalArgumentException e) {
         return null;
      }
   }

   /**
    * 模糊匹配转换为枚举,给定一个值,匹配枚举中定义的所有字段名(包括name属性),一旦匹配到返回这个枚举对象,否则返回null
    *
    * @param <E>       枚举类型
    * @param enumClass 枚举类
    * @param value     值
    * @return 匹配到的枚举对象,未匹配到返回null
    */
   @SuppressWarnings("unchecked")
   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;
   }

   /**
    * 枚举类中所有枚举对象的name列表
    *
    * @param clazz 枚举类
    * @return name列表
    */
   public static List<String> getNames(Class<? extends Enum<?>> clazz) {
      final Enum<?>[] enums = clazz.getEnumConstants();
      if (null == enums) {
         return null;
      }
      final List<String> list = new ArrayList<>(enums.length);
      for (Enum<?> e : enums) {
         list.add(e.name());
      }
      return list;
   }

   /**
    * 获得枚举类中各枚举对象下指定字段的值
    *
    * @param clazz     枚举类
    * @param fieldName 字段名,最终调用getXXX方法
    * @return 字段值列表
    */
   public static List<Object> getFieldValues(Class<? extends Enum<?>> clazz, String fieldName) {
      final Enum<?>[] enums = clazz.getEnumConstants();
      if (null == enums) {
         return null;
      }
      final List<Object> list = new ArrayList<>(enums.length);
      for (Enum<?> e : enums) {
         list.add(ReflectUtil.getFieldValue(e, fieldName));
      }
      return list;
   }

   /**
    * 获得枚举类中所有的字段名<br>
    * 除用户自定义的字段名,也包括“name”字段,例如:
    *
    * <pre>
    *   EnumUtil.getFieldNames(Color.class) == ["name", "index"]
    * </pre>
    *
    * @param clazz 枚举类
    * @return 字段名列表
    * @since 4.1.20
    */
   public static List<String> getFieldNames(Class<? extends Enum<?>> clazz) {
      final List<String> names = new ArrayList<>();
      final Field[] fields = ReflectUtil.getFields(clazz);
      String name;
      for (Field field : fields) {
         name = field.getName();
         if (field.getType().isEnum() || name.contains("$VALUES") || "ordinal".equals(name)) {
            continue;
         }
         if (false == names.contains(name)) {
            names.add(name);
         }
      }
      return names;
   }

   /**
    * 通过 某字段对应值 获取 枚举,获取不到时为 {@code null}
    *
    * @param enumClass 枚举类
    * @param predicate 条件
    * @param <E>       枚举类型
    * @return 对应枚举 ,获取不到时为 {@code null}
    * @since 5.8.0
    */
   public static <E extends Enum<E>> E getBy(Class<E> enumClass, Predicate<? super E> predicate) {
      return Arrays.stream(enumClass.getEnumConstants())
            .filter(predicate).findFirst().orElse(null);
   }

   /**
    * 通过 某字段对应值 获取 枚举,获取不到时为 {@code null}
    *
    * @param condition 条件字段
    * @param value     条件字段值
    * @param <E>       枚举类型
    * @param <C>       字段类型
    * @return 对应枚举 ,获取不到时为 {@code null}
    */
   public static <E extends Enum<E>, C> E getBy(Func1<E, C> condition, C value) {
      Class<E> implClass = LambdaUtil.getRealClass(condition);
      if (Enum.class.equals(implClass)) {
         implClass = LambdaUtil.getRealClass(condition);
      }
      return Arrays.stream(implClass.getEnumConstants()).filter(e -> condition.callWithRuntimeException(e).equals(value)).findAny().orElse(null);
   }

   /**
    * 通过 某字段对应值 获取 枚举,获取不到时为 {@code defaultEnum}
    *
    * @param <E>         枚举类型
    * @param <C>         字段类型
    * @param condition   条件字段
    * @param value       条件字段值
    * @param defaultEnum 条件找不到则返回结果使用这个
    * @return 对应枚举 ,获取不到时为 {@code null}
    * @since 5.8.8
    */
   public static <E extends Enum<E>, C> E getBy(Func1<E, C> condition, C value, E defaultEnum) {
      return ObjectUtil.defaultIfNull(getBy(condition, value), defaultEnum);
   }

   /**
    * 通过 某字段对应值 获取 枚举中另一字段值,获取不到时为 {@code null}
    *
    * @param field     你想要获取的字段
    * @param condition 条件字段
    * @param value     条件字段值
    * @param <E>       枚举类型
    * @param <F>       想要获取的字段类型
    * @param <C>       条件字段类型
    * @return 对应枚举中另一字段值 ,获取不到时为 {@code null}
    * @since 5.8.0
    */
   public static <E extends Enum<E>, F, C> F getFieldBy(Func1<E, F> field,
                                           Function<E, C> condition, C value) {
      Class<E> implClass = LambdaUtil.getRealClass(field);
      if (Enum.class.equals(implClass)) {
         implClass = LambdaUtil.getRealClass(field);
      }
      return Arrays.stream(implClass.getEnumConstants())
            // 过滤
            .filter(e -> condition.apply(e).equals(value))
            // 获取第一个并转换为结果
            .findFirst().map(field::callWithRuntimeException).orElse(null);
   }

   /**
    * 获取枚举字符串值和枚举对象的Map对应,使用LinkedHashMap保证有序<br>
    * 结果中键为枚举名,值为枚举对象
    *
    * @param <E>       枚举类型
    * @param enumClass 枚举类
    * @return 枚举字符串值和枚举对象的Map对应,使用LinkedHashMap保证有序
    * @since 4.0.2
    */
   public static <E extends Enum<E>> LinkedHashMap<String, E> getEnumMap(final Class<E> enumClass) {
      final LinkedHashMap<String, E> map = new LinkedHashMap<>();
      for (final E e : enumClass.getEnumConstants()) {
         map.put(e.name(), e);
      }
      return map;
   }

   /**
    * 获得枚举名对应指定字段值的Map<br>
    * 键为枚举名,值为字段值
    *
    * @param clazz     枚举类
    * @param fieldName 字段名,最终调用getXXX方法
    * @return 枚举名对应指定字段值的Map
    */
   public static Map<String, Object> getNameFieldMap(Class<? extends Enum<?>> clazz, String fieldName) {
      final Enum<?>[] enums = clazz.getEnumConstants();
      if (null == enums) {
         return null;
      }
      final Map<String, Object> map = MapUtil.newHashMap(enums.length, true);
      for (Enum<?> e : enums) {
         map.put(e.name(), ReflectUtil.getFieldValue(e, fieldName));
      }
      return map;
   }

   /**
    * 判断某个值是存在枚举中
    *
    * @param <E>       枚举类型
    * @param enumClass 枚举类
    * @param val       需要查找的值
    * @return 是否存在
    */
   public static <E extends Enum<E>> boolean contains(final Class<E> enumClass, String val) {
      return EnumUtil.getEnumMap(enumClass).containsKey(val);
   }

   /**
    * 判断某个值是不存在枚举中
    *
    * @param <E>       枚举类型
    * @param enumClass 枚举类
    * @param val       需要查找的值
    * @return 是否不存在
    */
   public static <E extends Enum<E>> boolean notContains(final Class<E> enumClass, String val) {
      return false == contains(enumClass, val);
   }

   /**
    * 忽略大小检查某个枚举值是否匹配指定值
    *
    * @param e   枚举值
    * @param val 需要判断的值
    * @return 是非匹配
    */
   public static boolean equalsIgnoreCase(final Enum<?> e, String val) {
      return StrUtil.equalsIgnoreCase(toString(e), val);
   }

   /**
    * 检查某个枚举值是否匹配指定值
    *
    * @param e   枚举值
    * @param val 需要判断的值
    * @return 是非匹配
    */
   public static boolean equals(final Enum<?> e, String val) {
      return StrUtil.equals(toString(e), val);
   }
}