使用valueOf前必须进行校验
每個枚舉都是java.lang.Enum的子類,都可以訪問Enum類提供的方法,比如hashCode(),name(),valueOf()等.....
其中valueOf()方法會把一個String類型的名稱轉(zhuǎn)變?yōu)槊杜e項,也就是枚舉項中查找出字面值與該參數(shù)相等的枚舉項,雖然這個方法很簡單,但是JDK卻做了一個對于開發(fā)人員來說并不簡單的處理:
看代碼:
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("無相關(guān)枚舉項"); 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.summerat 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轉(zhuǎn)換成枚舉類型可能不成功的情況,比如沒有匹配到指定的值,此時valueof的返回值應(yīng)該為空,所以后面又緊跟著if....else判斷輸出.
但是運行結(jié)果拋出異常.報告是無效參數(shù)異常...也就說summer(小寫s)午飯轉(zhuǎn)換為Season枚舉,無法轉(zhuǎn)換那也不應(yīng)該拋出IllegalArgumentException異常啊,一旦拋出這個異常,后續(xù)的代碼就不能執(zhí)行了,這才是要命的,
這與我們的習(xí)慣用法不一致,例如我們從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(//最后報無效參數(shù)異常 9 "No enum constant " + enumType.getCanonicalName() + "." + name); 10 }valueOf方法先通過反射從枚舉類的常量聲明中查找,若找到就直接返回,若找不到就拋出無效參數(shù)異常.
valueOf方法本意是保護編碼中的枚舉安全性,使其不產(chǎn)生空枚舉對象,簡化枚舉操作,但是又引入了一個我們無法避免的IllegalArgumentException異常.
可能有讀者會所此處valueOf()方法的源代碼不對,以上源代碼是要輸入兩個參數(shù),而我們的Season.valueOf()值傳遞一個String類型的參數(shù).
真的是這樣嗎?是的,因為valueOf(String name)方法是不可見的,是JVM內(nèi)置的方法,我們只有通過閱讀公開的valueOf方法來了解其運行原理.
在Season枚舉類中引用valueOf方法有三個:
但是在Enum的源碼中只有一個valueOf()的方法: 其他兩個方法都是JVM的內(nèi)置方法...
問題清楚了,我們有兩種方式可以解決處理此問題:
(1)使用try....catch捕獲異常
try {Season s = Season.valueOf(name);// 有該枚舉項時的處理 System.out.println(s);} catch (Exception e) {System.out.println("無相關(guān)枚舉項");}?
(2)擴展枚舉類:
由于Enum類定義的方法基本上都是final類型的,所以不希望被覆寫,那我們可以學(xué)習(xí)List和String,通過增加一個contains方法來判斷是否包含指定的枚舉項,然后再繼續(xù)轉(zhuǎn)換,看代碼:
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枚舉具備了靜態(tài)方法contains()之后,就可以在valueOf前判斷一下是否包含指定的枚舉名稱了,若包含則可以通過valueOf轉(zhuǎn)換為Season枚舉,若不包含則不轉(zhuǎn)換.
總結(jié)代碼:
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("無相關(guān)枚舉項"); 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("無相關(guān)枚舉項"); 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 }?
本文轉(zhuǎn)自SummerChill博客園博客,原文鏈接:http://www.cnblogs.com/DreamDrive/p/5632706.html,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的使用valueOf前必须进行校验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017阿里技术年度精选(全)
- 下一篇: Spring properties定义b