1. 程式人生 > 其它 >JDK1.7新特性(2):異常和可變長引數處理

JDK1.7新特性(2):異常和可變長引數處理

異常

jdk1.7對try--catch--finally的異常處理模式進行了增強,下面我們依次來看增強的方面。

  1. 為了防止異常覆蓋,給Throwable類增加了addSuppressed方法,可以將一個異常資訊追加到另一個異常資訊之後:

 1     /**
 2      * 這是第一種防止前面異常被覆蓋的方法,通過在finally塊中判斷前面是否有異常丟擲
 3      * 如果有則最終丟擲的異常為原來的異常,沒有則最終丟擲的異常為finally塊中的異常。
 4      * 此時只能丟擲一種異常資訊。
 5      * @param fileName
 6      */
 7     private void readFile(String fileName) {
 8         FileInputStream input = null;
 9         IOException readException = null;
10         try {
11             input = new FileInputStream(fileName);
12         } catch (IOException ex) {
13             readException = ex;
14         } finally {
15             if (input != null) {
16                 try {
17                     input.close();
18                 } catch (IOException e) {
19                     // 如果前面沒有出現異常,則說明整個異常是此處產生的
20                     if (readException == null) {
21                         readException = e;
22                     }
23                 }
24             }
25             
26             if (readException != null) {
27                 throw new RuntimeException(readException);
28             }
29         }
30     }
31     
32     /**
33      * 這是第二種防止異常被覆蓋的方法,利用jdk7的新特性。通過在finally塊的異常捕獲程式碼中判斷前面是否丟擲異常,如果丟擲異常
34      * 則將finally塊中丟擲的異常追加在前面的異常資訊之後。這樣同時可以丟擲兩種異常資訊型別。
35      * @param fileName
36      */
37     private void readFile2(String fileName) {
38         FileInputStream input = null;
39         IOException readException = null;
40         try {
41             input = new FileInputStream(fileName);
42         } catch (FileNotFoundException e) {
43             readException = e;
44         } finally {
45             if (input != null) {
46                 try {
47                     input.close();
48                 } catch (IOException e) {
49                     // 如果前面丟擲的異常不為空,這裡將finally塊中的異常資訊新增到原異常資訊後面
50                     if (readException != null) {
51                         readException.addSuppressed(e);
52                     } else {
53                         readException = e;
54                     }
55                 }
56             }
57             if (readException != null) {
58                 throw new RuntimeException(readException);
59             }
60         }
61     }

  2. catch塊增強,可以同時捕獲多個異常,來進行統一的處理:

 1     /**
 2      * 這裡測試jdk7的新特性,一個catch語句中可以捕獲多種異常,以 | 分割。
 3      */
 4     private void catchMore() {
 5         // 在jdk1.7新特性這本書中說一個catch塊中可以同時捕獲屬於父子關係的異常(只要子在前父在後,同分開的catch塊中的順序),但實際上在jdk1.8中時不允許的。
 6         try {
 7             int a = Integer.valueOf("aaa");
 8             throw new IOException();
 9         }  
10         /*
11             會報NumberFormatException已經被捕獲
12             catch (NumberFormatException | RuntimeException | IOException e) {
13             
14         }*/ catch (NumberFormatException | IOException e) {
15             
16         } catch (RuntimeException e) {
17         }
18     }

  3. throw語句增強,異常在第二次丟擲之後,仍然能夠準確的知道最原始的異常型別:

 1     /**
 2      * jdk1.7之後,即使異常被重新丟擲,編譯器也知道原始異常型別,而不會被再丟擲的異常型別所幹擾。
 3      * 如果在jdk1.6或者之前的版本,第二個catch只能是ExceptionA,因為原始的ExceptionASub2被抹去了。
 4      */
 5     private void testRecatch() {
 6         try {
 7             throw new ExceptionASub2();
 8         } catch (ExceptionA e) {
 9             try {
10                 throw e;
11             } catch (ExceptionASub2 e2) {   // 如果是catch (ExceptionASub1 e2) 那麼會報編譯錯誤,因為編譯器知道原始異常是ExceptionASub2
12                 
13             }
14         }
15     }
16 
17 class ExceptionA extends Exception {}
18 class ExceptionASub1 extends ExceptionA {}
19 class ExceptionASub2 extends ExceptionA {}

  4. try語句增強,try塊可以進行資源管理:

 1     /**
 2      * jdk1.7之後,對try塊進行了增強,使其中宣告的資源總是可以正確的被釋放,而不需要多餘的finally塊來單獨處理。
 3      * 這有點像python的 with open("a.txt") as file 語句一樣。
 4      * 需要注意的是,此時資源必須實現AutoCloseable介面,實際上jdk1.7中通過
 5      * public interface Closeable extends AutoCloseable,將Closeable繼承於AutoCloseable介面。
 6      * 如果我們要自己實現資源的關閉,只需直接實現AutoCloseable介面即可。
 7      */
 8     private void tryWithResource() {
 9         String fileName = "a.txt";
10         try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
11             
12         } catch (FileNotFoundException e) {
13             
14         } catch (IOException e) {
15             
16         }
17     }

變長引數

jdk1.7在變長引數和範型結合使用的時候,增加了一個@SafeVarargs。通過該註解來告訴編譯器引數型別的安全性,以此來解決每次呼叫都出現編譯警告的問題。

 1     /**
 2      * 在jdk1.7之前,需要使用@SuppressWarnings("unchecked")註解來給每一個呼叫該方法的地方取消警告
 3      * 。這是因為變長引數的實際值時通過陣列來傳遞的,而陣列中傳遞的時不可具化的範型物件,自身存在型別安全問題,所以編譯器
 4      * 會給出警告。這在呼叫java.utils.Arrays.asList方法和java.util.Collections.addAll方法中也會遇到。
 5      * jdk1.7中提供了在該方法宣告的地方加上@SafeVarargs註解。來表示該方法在與範型結合使用的時候不會出現型別安全問題。
 6      * 此時再呼叫該方法,編譯器不會給出警告資訊。
 7      * 不過需要注意的是,該方法必須宣告為static或者final方法,否則會出現編譯錯誤。
 8      */
 9     @SafeVarargs
10     public static<T> T useVarargs(T... args) {
11         return args.length > 0 ? args[0] : null;
12     }