每个枚举都是java.lang.Enum的子类,都可以访问Enum类提供的方法,比如hashCode(),name(),valueOf()等…..
其中valueOf()方法会把一个String类型的名称转变为枚举项,也就是枚举项中查找出字面值与该参数相等的枚举项,虽然这个方法很简单,但是JDK却做了一个对于开发人员来说并不简单的处理:
看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.Arrays;import java.util.List;public class Client { public static void main (String[] args) { List<String> params = Arrays.asList("Spring" , "summer" ); for (String name : params) { Season s = Season.valueOf(name); if (s != null ) { System.out.println(s); } else { System.out.println("无相关枚举项" ); } } } } enum Season { Spring, Summer, Autumn, Winter; }
运行输出:
1 2 3 4 5 Spring Exception in thread "main" java.lang.IllegalArgumentException: No enum constant cn.summerchill.test.Season.summer at java.lang.Enum.valueOf(Unknown Source) at cn.summerchill.test.Season.valueOf(Client.java:1) at cn.summerchill.test.Client.main(Client.java:12)
这段代码看起来很完美了,其中考虑到从String转换成枚举类型可能不成功的情况,比如没有匹配到指定的值,此时valueof的返回值应该为空,所以后面又紧跟着if….else判断输出.
但是运行结果抛出异常.报告是无效参数异常…也就说summer(小写s)午饭转换为Season枚举,无法转换那也不应该抛出IllegalArgumentException异常啊,一旦抛出这个异常,后续的代码就不能执行了,这才是要命的,
这与我们的习惯用法不一致,例如我们从List中查找一个元素,即使不存在也不会报错,顶多indexOf方法返回-1.
看源码:
1 2 3 4 5 6 7 8 9 public static <T extends Enum <T>> T valueOf (Class<T> enumType, String name) { T result = enumType.enumConstantDirectory().get(name); if (result != null ) return result; if (name == null ) throw new NullPointerException ("Name is null" ); throw new IllegalArgumentException ( "No enum constant " + enumType.getCanonicalName() + "." + name); }
valueOf方法先通过反射从枚举类的常量声明中查找,若找到就直接返回,若找不到就抛出无效参数异常.
valueOf方法本意是保护编码中的枚举安全性,使其不产生空枚举对象,简化枚举操作,但是又引入了一个我们无法避免的IllegalArgumentException异常.
可能有读者会所此处valueOf()方法的源代码不对,以上源代码是要输入两个参数,而我们的Season.valueOf()值传递一个String类型的参数.
真的是这样吗?是的,因为valueOf(String name)方法是不可见的,是JVM内置的方法,我们只有通过阅读公开的valueOf方法来了解其运行原理.
在Season枚举类中引用valueOf方法有三个: valueOf(String arg0): Season-Season, values():Season[], valueOf(Class enumType, String name):T-Enum
但是在Enum的源码中只有一个valueOf()的方法: 其他两个方法都是JVM的内置方法…
问题清楚了,我们有两种方式可以解决处理此问题: (1)使用try….catch捕获异常
1 2 3 4 5 6 7 try { Season s = Season.valueOf(name); System.out.println(s); } catch (Exception e) { System.out.println("无相关枚举项" ); }
(2)扩展枚举类: 由于Enum类定义的方法基本上都是final类型的,所以不希望被覆写,那我们可以学习List和String,通过增加一个contains方法来判断是否包含指定的枚举项,然后再继续转换,看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 enum Season { Spring, Summer, Autumn, Winter; public boolean contains (String _name) { Season[] season = values(); for (Season s:season){ if (s.name().equals(_name)){ return true ; } } return false ; } }
Season枚举具备了静态方法contains()之后,就可以在valueOf前判断一下是否包含指定的枚举名称了,若包含则可以通过valueOf转换为Season枚举,若不包含则不转换.
总结代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.Arrays;import java.util.List;public class Client { public static void main (String[] args) { List<String> params = Arrays.asList("Spring" , "summer" ); for (String name : params) { if (Season.contains(name)) { Season s = Season.valueOf(name); System.out.println(s); } else { System.out.println("无相关枚举项" ); } } } } enum Season { Spring, Summer, Autumn, Winter; public static boolean contains (String name) { Season[] season = values(); for (Season s : season) { if (s.name().equals(name)) { return true ; } } return false ; } }
ref:http://www.cnblogs.com/DreamDrive/p/5632706.html