在 GitHub 上查看。
在你知道输入有效的时候,使用Enum.valueOf非常棒。但是,如果传入无效的名称,那么将抛出异常。在某些情况下,这很好。不过,在通常情况下,我们宁愿忽略异常并返回null。
log.debug("Running valueOf"); for (String name : names) { try { log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.valueOf(name))); } catch (Exception ex) { log.warn("Exception Thrown", ex); } }
2017-02-22 14:46:38.556 [main] DEBUG c.s.examples.common.EnumLookup - Running valueOf 2017-02-22 14:46:38.804 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"} 2017-02-22 14:46:38.806 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"} 2017-02-22 14:46:38.806 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"} 2017-02-22 14:46:38.806 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"} 2017-02-22 14:46:38.808 [main] WARN c.s.examples.common.EnumLookup - Exception Thrown java.lang.IllegalArgumentException: No enum constant com.stubbornjava.examples.common.EnumLookup.CardSuit.Missing at java.lang.Enum.valueOf(Enum.java:238) at com.stubbornjava.examples.common.EnumLookup$CardSuit.valueOf(EnumLookup.java:1) at com.stubbornjava.examples.common.EnumLookup.main(EnumLookup.java:154)
很不幸的是,以下两种方法在代码库中出现得是这么的频繁。反面例子,勿学。
这种拙劣的做法最常见于初学者。异常不应该用于控制流,并且这样可能会有一些性能影响。不要偷懒。你必须用正确的方式去做。
/* * Please don't do this! Using try / catch for * control flow is a bad practice. */ public static CardSuit trycatchValueOf(String name) { try { return CardSuit.valueOf(name); } catch (Exception ex) { log.warn("Exception Thrown", ex); return null; } }
log.debug("Running trycatchValueOf"); for (String name : names) { log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.trycatchValueOf(name))); }
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - Running trycatchValueOf 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"} 2017-02-22 14:46:38.809 [main] WARN c.s.examples.common.EnumLookup - Exception Thrown java.lang.IllegalArgumentException: No enum constant com.stubbornjava.examples.common.EnumLookup.CardSuit.Missing at java.lang.Enum.valueOf(Enum.java:238) at com.stubbornjava.examples.common.EnumLookup$CardSuit.valueOf(EnumLookup.java:1) at com.stubbornjava.examples.common.EnumLookup$CardSuit.trycatchValueOf(EnumLookup.java:89) at com.stubbornjava.examples.common.EnumLookup.main(EnumLookup.java:171) 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
这种方法也很常见(见这里),但至少程序员知道不能用try/catch来捕获异常。那么,这种方法有什么问题呢?没错,它会迭代所有枚举,直到找到匹配的枚举或返回null——最坏的情况下需要n次,其中n就是枚举值的数量。有些人可能会认为这微不足道,这是过早优化了而已。但是,数据结构和算法是CS基础。使用Map而不是迭代集合要省力得多。这会大大提高性能吗?不,但它是一个很好的习惯。在面试候选人时,你会对线性复杂度搜索算法感到满意吗?此时,你不应该让这样的代码审查通过。
/* * Please don't do this! It is inefficient and it's * not very hard to use Guava or a static Map as an index. */ public static CardSuit iterationFindByName(String name) { for (CardSuit suit : CardSuit.values()) { if (name.equals(suit.name())) { return suit; } } return null; }
log.debug("Running iteration"); for (String name : names) { log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.iterationFindByName(name))); }
2017-02-22 14:46:38.808 [main] DEBUG c.s.examples.common.EnumLookup - Running iteration 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"} 2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
我们可以用谷歌的Guava Enums解决ValueOf中找到枚举的异常:
Enums提供了几个操作Enum的便利方法
常用方法
Field getField(Enum<?> enumValue): 返回变量名为enumValue变量值的Field
<T extends Enum<T>> Function<String, T> valueOfFunction(Class<T> enumClass): 返回一个可以将enum名字字符串转换成指定类型的enum的, 如果enum不存在时,Function将返回null
Optional<T> getIfPresent(Class<T> enumClass, String value): 使用Enum.valueOf()来返回指定名称和class的Enum的Optional,如果不存在则返回Absent, 常见用法Enums.getIfPresent(Country.class, countryInput).or(Country.DEFAULT)
代码:
package simplefactory; import com.google.common.base.Enums; import java.lang.reflect.InvocationTargetException; /** * @author 黄豪强 * @create 2019/7/24 16:11 */ public class RealObjectImpl implements RealObject { public Object select(String name) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { StarEmue aa = Enums.getIfPresent(StarEmue.class, name).or(StarEmue.NoStar); String a = aa.getS(); Class star = Class.forName(a); return star.newInstance(); } }
枚举:
package simplefactory; /** * @author 黄豪强 * @create 2019/7/25 9:50 */ public enum StarEmue { James("simplefactory.James"), Jodren("simplefactory.Jodren"),NoStar("simplefactory.NoStar"); private String s; private StarEmue(String s) { this.s = s; } public String getS() { return s; } public void setS(String s) { this.s = s; } }