[改善Java代码]使用valueOf前必须进行校验
每个枚举都是java.lang.Enum的子类,都可以访问Enum类提供的方法,比如hashCode(),name(),valueOf()等.....
其中valueOf()方法会把一个String类型的名称转变为枚举项,也就是枚举项中查找出字面值与该参数相等的枚举项,虽然这个方法很简单,但是JDK却做了一个对于开发人员来说并不简单的处理:
看代码:
import java.util.Arrays;
import java.util.List; public class Client {
public static void main(String[] args) {
//注意summer是小写
List<String> params = Arrays.asList("Spring", "summer");
for (String name : params) {
//查找表面值与name相同的枚举项
Season s = Season.valueOf(name);
if (s != null) {
// 有该枚举项时的处理
System.out.println(s);
} else {
// 没有该枚举项时的逻辑处理
System.out.println("无相关枚举项");
}
} } } enum Season {
Spring, Summer, Autumn, Winter;
}
运行输出:
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.
看源码:
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方法有三个:

但是在Enum的源码中只有一个valueOf()的方法: 其他两个方法都是JVM的内置方法...

问题清楚了,我们有两种方式可以解决处理此问题:
(1)使用try....catch捕获异常
            try {
                Season s = Season.valueOf(name);
                // 有该枚举项时的处理
                System.out.println(s);
            } catch (Exception e) {
                System.out.println("无相关枚举项");
            }
(2)扩展枚举类:
由于Enum类定义的方法基本上都是final类型的,所以不希望被覆写,那我们可以学习List和String,通过增加一个contains方法来判断是否包含指定的枚举项,然后再继续转换,看代码:
 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枚举,若不包含则不转换.
总结代码:
import java.util.Arrays;
import java.util.List; public class Client {
public static void main(String[] args) {
// 注意summer是小写
List<String> params = Arrays.asList("Spring", "summer");
for (String name : params) {
// 查找表面值与name相同的枚举项
// Season s = Season.valueOf(name);
// if (s != null) {
// // 有该枚举项时的处理
// System.out.println(s);
// } else {
// // 没有该枚举项时的逻辑处理
// System.out.println("无相关枚举项");
// }
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;
}
}
[改善Java代码]使用valueOf前必须进行校验的更多相关文章
- [改善Java代码]异常只为异常服务
		
异常原本是正常逻辑的补充,但是有时候会被当做主逻辑使用.看如下代码: public class Client { enum Color { Red, Blue; } public static voi ...
 - [改善Java代码]易变业务使用脚本语言编写
		
建议16: 易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP.Ruby.Groovy.JavaScript等,这些“入侵者”都有一个共同特征:全是同一类语言—脚本语言,它们 ...
 - 提高你的Java代码质量吧:使用valueof前必须进行校验
		
一.分析 每个枚举都是java.lang.Enum的子类,都可以访问Enum类提供的方法,比如hashCode.name.valueOf等,其中valueOf方法会把一个String类型的名称转变成枚 ...
 - [改善Java代码]推荐在复杂字符串操作中使用正则表达式
		
一.分析 字符串的操作,诸如追加.合并.替换.倒序.分隔等,都是在编码过程中经常用到的,而且Java也提供了append.replace.reverse.split等方法来完成这些操作,它们使用起来 ...
 - [改善Java代码]多线程使用Vector或HashTable
		
Vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本,这些概念我 们都很清楚,也被前辈嘱咐过很多次,但我们经常会逃避使用Vector和HashTable,因为用 ...
 - [改善Java代码]减少HashMap中元素的数量
		
在系统开发中我们经常会使用HashMap作为数据集容器,或者是用缓冲池来处理,一般很稳定,但偶尔也会出现内存溢出的问题(OutOfMemory错误),而且这经常是与HashMap有关的.而且这经常是与 ...
 - [改善Java代码]不同的列表选择不同的遍历方法
		
一.场景: 我们来看一个场景,统计一个省的各科高考科目考试的平均分. 当然使用数据库中的一个SQL语句就能求出平均值,不过这个不再我们的考虑之列,这里只考虑使用纯Java的方式来解决.(由于我的机器配 ...
 - [改善Java代码]枚举和注解结合使用威力更大
		
注解的写法和接口很类似,都采用了关键字interface,而且都不能有实现代码,常量定义默认都是pulbic static final类型的. 他们的主要不同点是:注解在interface前加上@字符 ...
 - [改善Java代码]强制声明泛型的实际类型
		
Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. import java.util.Ar ...
 
随机推荐
- Spark SQL概念学习系列之如何使用 Spark SQL(六)
			
val sqlContext = new org.apache.spark.sql.SQLContext(sc) // 在这里引入 sqlContext 下所有的方法就可以直接用 sql 方法进行查询 ...
 - JavaScript如何判断参数为浮点型
			
在codewars里,确实可以学到很多很酷的方法,例如这一次的题目是判断数字是否为浮点型.我一开始是想有没有原生的js方法,像isNaN(),isFinite(),在前者Infinity是不属于NaN ...
 - 设置VMWARE通过桥接方式使用主机网卡上网
			
1 Host-only连接方式 让虚机具有与宿主机不同的各自独立IP地址,但与宿主机位于不同网段,同时为宿主主机新增一个IP地址,且保证该IP地址与各虚机IP地址位于同一网段.最终结果是新建了一个由 ...
 - 如何在不装ORACLE的情况下使用PLSQL
			
原来我电脑装了oracle跟plsql,然后使用plsql的.后来因为某些原因,我重装了系统,把装的软件都格调了,需要重新装.当时在装plsql的时候我就想,我一直都是直接用plsql远程连接的服务器 ...
 - HDU 4370 0 or 1 (最短路+最小环)
			
0 or 1 题目链接: Rhttp://acm.hust.edu.cn/vjudge/contest/122685#problem/R Description Given a n*n matrix ...
 - [iOS基础控件 - 6.9] 聊天界面Demo
			
A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话 ...
 - 通过java发送http请求
			
通常的http请求都是由用户点击某个连接或者按钮来发起的,但是在一些后台的Java程序中需要发送一些get或这post请求,因为不涉及前台页面,该怎么办呢? 下面为大家提供一个Java发送http请求 ...
 - Spring Batch Concepts Chapter
			
Spring Batch Concepts Chapter The below figure shows two kinds of Spring Batch components:infrastruc ...
 - URAL 1774 A - Barber of the Army of Mages 最大流
			
A - Barber of the Army of MagesTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/v ...
 - Ogre分层渲染 (转)
			
Ogre分层渲染 转载请注明出处!http://www.cnblogs.com/pulas 在超大的场景中,如果既想看到近处的物体,又想看到很远的物体,则必须把相机的远近裁剪面距离设得很大.远近裁剪面 ...