贊!7000 字學習筆記,一天搞定 MySQL
阿新 • • 發佈:2020-07-06
1 java的異常處理機制
1.1 異常在java中以類和物件的形式存在。那麼異常的繼承結構是怎麼樣的?
我們可以使用UML圖來描述一下結構繼承。
畫UML圖有很多工具,例如:Rational Rose(收費的)、startUML等...
Object
Object下有Throwable(可丟擲的)
Throwable下有兩個分支:Error(不可處理的,直接退出JVM)和Exception(可處理的)
Exception下有兩個分支:
Exception的直接子類:編譯時異常。(要求程式設計師在編寫程式階段必須預先對這些異常進行處理,如果不處理編譯器報錯,因此得名編譯時異常。)
RuntimeException:執行時異常。(在編寫程式階段程式設計師可以預先處理,也可以不管,都行。)
1.2 編譯時異常和執行是異常,都是發生在執行階段。編譯階段異常是不會發生的。
編譯時異常因為什麼而得名?
因為編譯時異常必須在編譯(編寫)階段預先處理,如果不處理編譯器報錯,因此得名。
所有一摻個都是在執行階段發生的,因為只有程式執行階段才可以new物件。
因為異常的發生就是new異常物件。
1.3 編譯時異常和執行時異常的區別?
編譯時異常一般發生的概率比較高。
執行時異常一般發生的概率比較低。
舉個例子:
你看到外面下雨了,傾盆大雨的。
你出門之前會預料到:如果不打傘,我可能會生病(生病是一種異常)。
而且這個異常發生的概率很高,所以我們出門之前要拿一把傘。
對於一些發生概率較高的異常,需要在執行之前對其進行預處理。
執行時異常一般發生的概率比較低。
舉個例子:
小明走在大街上,可能會被天上的飛機輪子砸到。
被飛機輪子砸到也算一種異常。
但是這種異常發生概率較低。
再出門之前你沒必要提前對這種發生概率較低的異常進行預處理。
如果你預處理這種異常,你將活的很累。
假設你再出門之前,你把能夠發生的異常都預先處理,你這個人會更加的安全,但是你這個人活的很累。
假設java中沒有對異常進行劃分,沒有分為:編譯時異常和執行時異常。
所有的異常都需要在編寫階段對其進行預處理,將是怎樣的效果呢?
首先,如果這樣的話,程式肯定是絕對安全的。
但是程式設計師編寫程式太累,程式碼到處都是處理異常的程式碼。
1.4 編譯時異常還有其他名字:
受檢異常:CheckdException
受控異常
1.5 執行時異常還有其他名字:
未受控異常:UnCheckdException
非受控異常。
1.6 再次強調:所有的異常都是發生在執行階段的。
1.7 java語言中對異常的處理包括兩種方式:
第一種方式:在方法生命的位置上,使用throws關鍵字,拋給上一級。
誰呼叫我,我就拋給誰。拋給上一級。
第二種方式:使用try..catch語句進行異常的捕捉。
這件事發生了,誰也不知道,因為我給抓住了。
舉個例子:
我是某集團的一個銷售員,因為我得失誤,導致公司損失了1000元,
“損失1000元”這可以看做是一個異常發生了。我有兩種處理方式,
第一種方式:我把這件事情告訴我的領導【異常上拋】
第二種方式:我自己掏腰包把這個錢補上。【異常的捕捉】
什麼是異常,java提供異常機制有什麼用?
package com.javase.Exception; /* 1 什麼是異常,java提供異常機制有什麼用? 以下程式執行過程中發生了不正常的情況,而這種不正常的情況叫做:異常 java語言是很完善的語言,提供了異常的處理方式,以下程式執行過程中出現了不正常情況, java把該異常資訊列印輸出到控制檯,供程式設計師參考。 程式設計師看到以後,可以對程式進行修改,讓程式更加的健壯。 什麼是異常:程式執行過程中的不正常情況。 異常的作用:增強程式的健壯性。 2 以下程式執行控制檯出現了: Exception in thread "main" java.lang.ArithmeticException: / by zero at com.javae.Exception.ExceptionTest01.main(ExceptionTest01.java:17) 這個資訊被我們稱作:異常資訊。這個資訊是JVM列印的。 */ public class ExceptionTest01 { public static void main(String[] args) { int a= 10; int b = 1; // 實際上JVM在執行到此處的時候,會new異常物件。 new ArithmeticException("/ by zero");物件 // 並且JVM將new的異常物件丟擲,列印輸出資訊到控制檯了。 int c = a / b; System.out.println(a +" / "+ b + " = " + c); // 此處執行也會建立一個:ArithmeticException型別的物件。 System.out.println(100 / 0); // 我觀察到異常資訊之後,對程式進行修改,更加健壯。 /*int a = 10; int b = 0; if(b == 0){ System.out.println("除數不能為0"); return; } // 程式執行到此處表示除數一定不是0 int c = a / b; System.out.println(a +" / "+ b + " = " + c);*/ } }java語言中異常是以什麼形式存在的呢?
package com.javase.Exception; /* java語言中異常是以什麼形式存在的呢? 1 異常在java中以類的形式存在,每一個異常都是一個類。 2 異常對應的現實生活中是怎樣的? 火災(異常類): 2008年8月8日小明家著火了(異常物件) 2008年8月18日小剛家著火了(異常物件) 2008年8月28日小紅家著火了(異常物件) 類是:模板。 物件是:實際存在的個體。 錢包丟了(異常類): 2008年1月8日:小明的錢包丟了(異常物件) 2008年1月9日:小明的錢包又丟了(異常物件) ... */ public class ExceptionTest02 { public static void main(String[] args) { // 通過"異常類"例項化"異常物件" NumberFormatException numberFormatException = new NumberFormatException("數字格式化異常"); // java.lang.NumberFormatException: 數字格式化異常 System.out.println(numberFormatException); // 通過“異常類”建立“異常物件” NullPointerException nullPointerException = new NullPointerException("空指標異常發生了"); // java.lang.NullPointerException: 空指標異常發生了 System.out.println(nullPointerException); } }ArithmeticException異常案例:
package com.javase.Exception; public class ExceptionTest03 { public static void main(String[] args) { /* 程式執行到此處發生了ArithmeticException: / by zero異常。 底層new了一個ArithmeticException異常物件。 然後丟擲了,由於是main方法呼叫了100/0 所以這個異常ArithmeticException拋給了main方法 main方法沒有處理,將這個異常拋給了JVM。 JVM最終終止程式的執行。 ArithmeticException繼承了RunTimeException,屬於執行時異常。 在編寫程式階段不需要對這種異常進行預先的處理。 */ System.out.println(100 / 0); // 這裡的Hello World沒有輸出,沒有執行。 System.out.println("Hello World"); } }
分析程式碼異常報錯原因案例:
package com.javase.Exception; /* 以下程式碼報錯的原因是什麼? 因為doSome()方法宣告位置上使用了throws ClassNotFoundException 而ClassNotFoundException是編譯時異常。必須編寫程式碼時處理,沒有處理編譯器報錯 */ public class ExceptionTest04 { public static void main(String[] args) { // main方法中呼叫doSome()方法 // 因為doSome()方法宣告位置上有:throws ClassNotFoundException // 我們在呼叫doSome()方法的時候必須對著彙總異常進行預先的處理。 // 如果不處理,編譯器就會報錯。 // 編譯器報錯資訊:Unhandled exception: java.lang.ClassNotFoundException // doSome(); } /** * doSome方法在宣告的位置使用了:throws ClassNotFoundException * 這個程式碼表示doSome()方法在執行過程中,有可能會出現ClassNotFoundException異常。 * 叫做類沒有找到異常,這個異常直接父類是:Exception,所以ClassNotFoundException屬於編譯時異常。 * @throws ClassNotFoundException */ public static void doSome() throws ClassNotFoundException{ System.out.println("doSome方法執行了"); } }異常的捕捉和上拋:
package com.javase.Exception; public class ExceptionTest05 { // 第一種處理方式:在宣告的位置上繼續使用:throws來完成異常的繼續上拋,拋給呼叫者。 // 上拋類似於推卸責任(繼續向上拋給呼叫者) /*public static void main(String[] args) throws ClassNotFoundException{ doSome(); }*/ // 第二種處理方式:try..catch進行捕捉 // 不做等於把異常攔下了,異常真正的解決了。(呼叫者是不知道的。) public static void main(String[] args) { try { doSome(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void doSome() throws ClassNotFoundException{ System.out.println("doSome方法執行了"); } }
異常的上報和捕捉:
package com.javase.Exception; import java.io.FileNotFoundException; import java.io.FileOutputStream; /* 處理異常的第一種方式:在方法宣告的位置使用throws關鍵字丟擲,誰呼叫我這個方法,我就拋給誰,拋給呼叫者處理。 這種處理異常的態度:上報。 處理異常的第二種方式: 使用try..catch語句對異常進行捕捉。 這個異常不會上報,自己把這個事處理了。 異常拋到此處為止,不在上拋了。 注意: 只要異常沒有捕捉,採用上報的方式,此方法的後續程式碼不會執行。 另外需要注意,try語句塊中的某一行出現異常,該行後面的程式碼不會執行。 try..catch執行完成後,該方法後面的java語句會執行。 */ public class ExceptionTest06 { // 一般不建議在main方法上使用throws,因為這個異常如果真正發生了,一定會拋給JVM、JVM只有終止。 // 異常處理機制的作用就是增強程式的健壯性,怎麼能做到、異常發生了也不影響程式的執行。 // 所以一般main方法中的異常建議使用try..catch進行捕捉,main就不要繼續向上拋了。 public static void main(String[] args) { System.out.println("main begin"); // try嘗試 try { m1(); // 以上程式碼出現異常,直接進入catch語句塊中執行。 } catch (FileNotFoundException e) { // catch後面的好像一個方法的形參 // 這個分支中可以使用e引用,e引用儲存的記憶體地址是那個new出來異常物件的記憶體地址。 // catch是捕捉 異常之後走的分支 // 在catch分支中幹什麼?處理異常。 System.out.println("檔案不存在,可能路徑錯誤!也可能該檔案被刪除了。"); System.out.println(e);// java.io.FileNotFoundException: C:哇哈哈哈哈哈哈哈哈.txt (拒絕訪問。) } // try..catch把異常抓住以後,這裡的程式碼會繼續執行。 System.out.println("main end"); } public static void m1() throws FileNotFoundException { System.out.println("m1 begin"); m2(); // 出現異常以下程式碼不會被執行 System.out.println("m1 end"); } // 拋別的不行,拋ClassCastException說明你還是沒有對FileNOtFoundException進行處理 // 拋FileNotFoundException的父類物件IOException,這樣是可以的。因為IOException包括FileNotFoundException // private static void m2() throws FileNotFoundException { // 這樣也可以,因為Exception包括所有的異常。 // private static void m2() throws Exception { // throws後面也可以寫多個異常,使用逗號隔開 // private static void m2() throws ClassNotFoundException,FileNotFoundException{ private static void m2() throws FileNotFoundException{ System.out.println("m2 begin"); m3(); // 出現異常以下程式碼不會被執行 System.out.println("m2 end"); } private static void m3() throws FileNotFoundException { // 呼叫SUN jdk中某個類的構造方法 // 這個類還沒有接觸過,後期IO流的時候就知道了。 // 我們只是藉助這個類學習一下異常處理機制。 // 建立一個輸入流物件,該流指向一個檔案。 System.out.println("m3 begin"); /* 編譯報錯的原因是什麼? 1 第一:這裡呼叫了一個構造方法:FileInputStream(String name) 2 第二:這個構造方法的宣告位置上有:throws FileNotFoundException 3 第三:通過類的繼承結構看到:FileNotFoundException的父類是IOException,IOException的父類是Exception 最終得知,FileNotFoundException是編譯時異常。 錯誤原因?編譯時異常要求程式設計師編寫程式階段必須對他進行處理,不處理編譯器報錯。 */ // 我們採用第一種處理方式:在方法宣告的位置上使用throws繼續上拋。 // new FileOutputStream("C:\\Users\\xlWu\\Desktop\\學習\\異常\\學習.txt"); new FileOutputStream("C:哇哈哈哈哈哈哈哈哈.txt"); // 出現異常以下程式碼不會被執行 System.out.println("m1 end"); } }深入try..catch:
package com.javase.Exception; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /* 深入try..catch 1 catch後面的小括號中的型別可以是具體的異常型別,也可以是該異常型別的父型別。 2 catch可以寫多個,建議catch的時候,精確的一個一個處理,這樣有利於程式的除錯。 3 catch寫多個的時候,從上到下,必須遵循從小到大。 在以後的開發中,處理編譯時異常,應該上報還是捕捉呢,怎麼選? 如果希望呼叫者來處理,選擇throws上報。 其它情況使用捕捉的方式。 */ public class ExceptionTest07 { /*public static void main(String[] args) throws Exception, FileNotFoundException,NullPointerException,NumberFormatException { }*/ /*public static void main(String[] args) throws Exception { }*/ public static void main(String[] args) { /*try { FileInputStream fis = new FileInputStream("D:\\Users\\xlWu\\Desktop\\學習\\異常\\異常的繼承結構圖.uml"); System.out.println("出現異常,這裡無法執行!"); } catch (FileNotFoundException e) { System.out.println("檔案不存在!"); } System.out.println("hello world!");*/ /*try { FileInputStream fis = new FileInputStream("D:\\Users\\xlWu\\Desktop\\學習\\異常\\異常的繼承結構圖.uml"); System.out.println("出現異常,這裡無法執行!"); *//*} catch (IOException e) {// 多型 IOException e = new FileNotFoundException();*//* } catch (Exception e) {// 多型 Exception e = new FileNotFoundException(); System.out.println("檔案不存在!"); }*/ /*try { // 建立輸入流 FileInputStream fis = new FileInputStream("D:\\Users\\xlWu\\Desktop\\學習\\異常\\異常的繼承結構圖.uml"); // 讀檔案 fis.read(); } catch (Exception e) { // 所有的異常都走這個分支 System.out.println("檔案不存在!"); }*/ /*try { // 建立輸入流 FileInputStream fis = new FileInputStream("D:\\Users\\xlWu\\Desktop\\學習\\異常\\異常的繼承結構圖.uml"); // 讀檔案 fis.read(); } catch (FileNotFoundException e) { System.out.println("檔案不存在!"); } catch (IOException e) { System.out.println("讀檔案報錯了!"); }*/ // 編譯報錯 自上而下執行 必須由小到大 /*try { // 建立輸入流 FileInputStream fis = new FileInputStream("D:\\Users\\xlWu\\Desktop\\學習\\異常\\異常的繼承結構圖.uml"); // 讀檔案 fis.read(); } catch (IOException e) { System.out.println("檔案不存在!"); } catch (FileNotFoundException e) { System.out.println("讀檔案報錯了!"); }*/ // JDK8的新特性 try { // 建立輸入流 FileInputStream fis = new FileInputStream("D:\\Users\\xlWu\\Desktop\\學習\\異常\\異常的繼承結構圖.uml"); // 進行數學運算 System.out.println(10 / 0);// 這個是執行時異常,編寫程式時可以處理,也可以不處理。 } catch (FileNotFoundException | ArithmeticException | NullPointerException e) { System.out.println("檔案不存在?數學異常?空指標異常?都有可能!"); } } }