使用valueOf前必须进行校验

简介:

每个枚举都是java.lang.Enum的子类,都可以访问Enum类提供的方法,比如hashCode(),name(),valueOf()等.....

其中valueOf()方法会把一个String类型的名称转变为枚举项,也就是枚举项中查找出字面值与该参数相等的枚举项,虽然这个方法很简单,但是JDK却做了一个对于开发人员来说并不简单的处理:

看代码:

复制代码
 1 import java.util.Arrays;
 2 import java.util.List;
 3 
 4 public class Client {
 5     public static void main(String[] args) {
 6         //注意summer是小写
 7         List<String> params = Arrays.asList("Spring", "summer");
 8         for (String name : params) {
 9             //查找表面值与name相同的枚举项
10             Season s = Season.valueOf(name);
11             if (s != null) {
12                 // 有该枚举项时的处理
13                 System.out.println(s);
14             } else {
15                 // 没有该枚举项时的逻辑处理
16                 System.out.println("无相关枚举项");
17             }
18         }
19         
20     }
21 
22 }
23 
24 enum Season {
25     Spring, Summer, Autumn, Winter;
26 }
复制代码

运行输出:

复制代码
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     public static <T extends Enum<T>> T valueOf(Class<T> enumType,
 2                                                 String name) {
 3         T result = enumType.enumConstantDirectory().get(name);//通过反射,从常量列表中查找.
 4         if (result != null)
 5             return result;
 6         if (name == null)
 7             throw new NullPointerException("Name is null");
 8         throw new IllegalArgumentException(//最后报无效参数异常
 9             "No enum constant " + enumType.getCanonicalName() + "." + name);
10     }
复制代码

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方法来判断是否包含指定的枚举项,然后再继续转换,看代码:

复制代码
 1 enum Season {
 2     Spring, Summer, Autumn, Winter;
 3     public boolean contains(String _name){
 4         Season[] season = values();
 5         for(Season s:season){
 6             if(s.name().equals(_name)){
 7                 return true;
 8             }
 9         }
10         return false;
11         
12     }
13 }
复制代码

 

 Season枚举具备了静态方法contains()之后,就可以在valueOf前判断一下是否包含指定的枚举名称了,若包含则可以通过valueOf转换为Season枚举,若不包含则不转换.

总结代码:

复制代码
 1 import java.util.Arrays;
 2 import java.util.List;
 3 
 4 public class Client {
 5     public static void main(String[] args) {
 6         // 注意summer是小写
 7         List<String> params = Arrays.asList("Spring", "summer");
 8         for (String name : params) {
 9             // 查找表面值与name相同的枚举项
10 //            Season s = Season.valueOf(name);
11 //            if (s != null) {
12 //                // 有该枚举项时的处理
13 //                System.out.println(s);
14 //            } else {
15 //                // 没有该枚举项时的逻辑处理
16 //                System.out.println("无相关枚举项");
17 //            }
18             if (Season.contains(name)) {
19                 Season s = Season.valueOf(name);
20                 // 有该枚举项时的处理
21                 System.out.println(s);
22             } else {
23 
24                 System.out.println("无相关枚举项");
25 
26             }
27 
28         }
29 
30     }
31 
32 }
33 
34 enum Season {
35     Spring, Summer, Autumn, Winter;
36 
37     // 是否包含指定名称的枚举项
38     public static boolean contains(String name) {
39         // 所有的枚举值
40         Season[] season = values();
41         
42         // 遍历查找
43         for (Season s : season) {
44             if (s.name().equals(name)) {
45                 return true;
46             }
47         }
48         return false;
49     }
50 }
复制代码

 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5632706.html,如需转载请自行联系原作者

相关文章
|
NoSQL Java 关系型数据库
蚂蚁金服+拼多多+抖音+天猫(技术三面)面经合集助你拿大厂offer
很多Java开发者面试之前,可能没有较长的工作时间或者较为丰富的工作经验,所以不知道互联网公司或者一线互联网公司技术面试都会问哪些问题? 再加上可能自己准备也不充分,去面试没几个回合就被面试官几个问题打蒙了,最后以惨败收场。针对这些的读者朋友,小编整理了一些知名大厂的面经,在这分享给读者朋友们参考,让即将面试或是有想法跳槽的读者朋友们了解一下一线大厂面试时都喜欢问那些问题。
|
SQL 存储 关系型数据库
对线面试官 - 如何理解MySQL的索引覆盖和索引下推
索引下推是MySQL 5.6引入的优化,允许部分WHERE条件在索引中处理,减少回表次数。例如,对于索引(zipcode, lastname, firstname),查询`WHERE zipcode=&#39;95054&#39; AND lastname LIKE &#39;%etrunia%&#39;`时,索引下推先过滤zipcode,然后在索引中应用lastname条件,降低回表需求。索引下推可在EXPLAIN的`Using index condition`中看到。
1684 0
对线面试官 - 如何理解MySQL的索引覆盖和索引下推
|
9天前
|
人工智能 自然语言处理 安全
OpenClaw从入门到精通:阿里云/本地保姆级部署步骤+必装Top10 Skills +免费模型配置一站式指南
2026年,OpenClaw(Clawdbot)已经成为AI智能体领域最主流的开源框架,凭借可本地部署、可云端托管、可技能扩展、可系统执行的超强能力,迅速成为个人效率、办公自动化、信息搜集、知识管理的首选平台。但很多用户在安装完OpenClaw后,往往不知道下一步该装哪些技能,也不清楚哪些技能真正实用、安全、高效。
652 0
|
网络协议 JavaScript API
深入浅出 WebSocket:实现实时 web 通信
在现代Web应用中,实时通信至关重要。WebSocket通过单个TCP连接实现全双工通信,允许服务器主动向客户端发送消息。本文介绍了WebSocket的核心概念、实现方法及其优势。WebSocket建立了持久连接,支持实时数据传输,减少服务器负载,并提供双向通信。通过JavaScript API可轻松建立连接、发送接收消息及处理异常。使用WebSocket,开发者能构建更动态的Web应用。
|
缓存 Java Nacos
图文详述Nacos服务发现源码分析
图文详述Nacos服务发现源码分析
2231 0
图文详述Nacos服务发现源码分析
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
详细介绍实现Java Spring Boot FCM推送教程
517 0
|
SQL 关系型数据库 MySQL
(十六)MySQL调优篇:单机数据库如何在高并发场景下健步如飞?
在当前的IT开发行业中,系统访问量日涨、并发暴增、线上瓶颈等各种性能问题纷涌而至,性能优化成为了现时代中一个炙手可热的名词,无论是在开发、面试过程中,性能优化都是一个常谈常新的话题。而MySQL作为整个系统的后方大本营,由于是基于磁盘的原因,性能瓶颈往往也会随着流量增大而凸显出来。
1863 0
|
Go Java
mockito中两种部分mock的实现,spy、callRealMethod
什么是类的部分mock(partial mock)?A:部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)。   为什么需要部分mock? A:当需要测试一个组合方法(一个方法需要其它多个方法协作)的时候,某个叶子方法(只供别人调用,自己不依赖其它反复)已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。
5279 1
|
存储 人工智能 算法
探索AI在后端开发中的应用与挑战
随着人工智能技术的飞速发展,AI在后端开发领域扮演着越来越重要的角色。本文将深入探讨AI在后端开发中的应用现状和面临的挑战,分析其带来的影响与发展趋势。
902 1
|
Java Apache
Java代码使用POI导出的单元格加上边框和背景色
【5月更文挑战第3天】Java代码使用POI导出的单元格加上边框和背景色
1651 0