JDK1.7新特性(2):異常和可變長引數處理
阿新 • • 發佈:2022-05-04
異常
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 }