1.什麼是異常
非正常的,不同於平常的.
生活中:醫生說,你的身體某個部位有異常,該部位和正常相比有點不同,該部位的功能將受影響.張三要開車去上班,正常情況下,應該是到達公司,上班.不正常的情況下,車子壞了,只能走路去,導致上班遲到.
程序中:在程序中,代碼出現錯誤,程序就會終止運行.
異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生字節碼文件,根本不能運行.
----------------------------------------
異常處理是衡量一門語言是否成熟的標準之一,主流的語言Java,C++,C#等支持異常處理機制.
異常處理機制可以讓程序有更好的容錯性,使我們的代碼更健壯.
遺憾的是傳統的C語言卻沒有異常,此時只能程序員通常使用方法的特定返回值來表示異常情況,並且使用if語句來判斷正常和非正常情況,那沒有異常會帶來什麼問題呢?
----------------------------------------
沒有異常機制存在的缺點:
1:使用方法的返回值來表示異常情況有限,無法窮舉所有的異常情況.
2:異常流程代碼和正常流程代碼混合一起,增大了程序的複雜性,可讀性也不好.
3:隨着系統規模的不斷擴大,程序的可維護性極低.
2.java的異常體系
1):Error:表示錯誤,一般指JVM相關的不可修復的錯誤,如,系統崩潰,內存溢出,JVM錯誤等,由JVM拋出,我們不需要處理.
幾乎所有的子類都是以Error作爲類名的後綴.
2):Exception:表示異常,指程序中出現不正常的情況,該問題可以修復(處理異常).
幾乎所有的子類都是以Exception作爲類名的後綴.
----------------------------------------------------------------------------------------------------
出現異常,不要緊張,把異常的簡單類名,拷貝到API中去查.
----------------------------------------------------------------------------------------------------
常見的Error:
StackOverflowError:當應用程序遞歸太深而發生內存溢出時,拋出該錯誤。
常見的Exception:
NullPointerException:空指針異常,一般指當對象爲null的時候,調用了該對象的方法,字段.
ArrayIndexOutOfBoundsException:數組的索引越界,(小於0或者大於等於數組長度)
NumberFormatException:數字格式化異常, 一般指,把非0~9的字符串轉換爲整數.
--------------------------------------------------------------
證明出現異常之後,程序會中斷,所以必須處理異常.
2.捕獲異常
如果異常出現的話,會立刻終止程序,所以我們得處理異常:
1):該方法不處理,而是聲明拋出,由該方法的調用者來處理(throws).
2):在方法中使用try-catch的語句塊來處理異常.
-----------------------------------------------------------------------
使用try-catch捕獲單個異常,語法如下:
try{
編寫可能會出現異常的代碼
}catch(異常類型 e){
處理異常的代碼
//記錄日誌/打印異常信息/繼續拋出異常
}
注意:try和catch都不能單獨使用,必須連用.
舉例:
1)正常情況
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- int ret = 10/2; //正常的結果
- System.out.println("結果="+ret);
- System.out.println("end------");
- }
- }
2)出現異常,程序會中斷執行
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- int ret = 10/0; //除數爲0,出現異常
- System.out.println("結果="+ret);
- System.out.println("end------");
- }
- }
可以看出程序出現異常後,程序會終止,這時我們需要處理異常
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- try{
- int ret = 10/0; //除數爲0,出現異常
- System.out.println("結果="+ret);
- }catch(ArithmeticException e){
- System.out.println("出異常啦!!!!");
- }
- System.out.println("end------");
- }
- }
分析:
可以看出異常出現後程序跳轉到catch塊兒執行,當catch塊兒的代碼執行完之後,程序並沒有停止,而是繼續執行後面的代碼
3.獲取異常信息
如何獲取異常信息,Throwable類的方法:
1):String getMessage():獲取異常的描述信息,原因(提示給用戶的時候,就提示錯誤原因).
2):String toString():獲取異常的類型和異常描述信息(不用).
3):void printStackTrace():打印異常的跟蹤棧信息並輸出到控制檯. 不需要使用System.out.println.
包含了異常的類型,異常的原因,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace.
記住:現在在catch語句塊中,必須寫:e.printStackTrace();目的:查看異常的具體信息,方便調試和修改.
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- try{
- int ret = 10/0; //除數爲0,出現異常
- System.out.println("結果="+ret);
- }catch(ArithmeticException e){
- System.out.println("異常信息"+e.toString()); //異常信息java.lang.ArithmeticException: / by zero
- System.out.println("異常信息"+e.getMessage()); //異常信息/ by zero
- //推薦使用下面這個
- e.printStackTrace();//自帶打印功能異常信息,java.lang.ArithmeticException: / by zero
- //at cn.anyglobe.ExceptionDemo1.main(ExceptionDemo1.java:8)
- }
- System.out.println("end------");
- }
- }
使用try-catch捕獲多個異常:
try{
編寫可能會出現異常的代碼
}catch(異常類型A e){ 當try中出現A類型異常,就用該catch來捕獲.
處理異常的代碼
//記錄日誌/打印異常信息/繼續拋出異常
}catch(異常類型B e){ 當try中出現B類型異常,就用該catch來捕獲.
處理異常的代碼
//記錄日誌/打印異常信息/繼續拋出異常
}
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- String sNum1 = "10"; //輸入的除數
- String sNum2 = "0"; //輸入的被除數
- try{
- int num1 = Integer.parseInt(sNum1);
- int num2 = Integer.parseInt(sNum2);
- int ret = num1/num2; //除數爲0,出現異常
- System.out.println("結果="+ret);
- }catch(ArithmeticException e){
- System.out.println("除數爲0");
- }catch (NumberFormatException e) {
- System.out.println("類型轉換異常");
- }
- System.out.println("end------");
- }
- }
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- String sNum1 = "10"; //輸入的除數
- String sNum2 = "0"; //輸入的被除數
- try{
- int num1 = Integer.parseInt(sNum1);
- int num2 = Integer.parseInt(sNum2);
- int ret = num1/num2; //除數爲0,出現異常
- System.out.println("結果="+ret);
- }catch(ArithmeticException e){
- System.out.println("除數爲0");
- }catch (NumberFormatException e) {
- System.out.println("類型轉換異常");
- }
- System.out.println("end------");
- }
- }
從上面兩個代碼可以看出,捕獲多個異常時,程序只需要一個catch捕獲,不可能同時出現多個異常.
如果不知道什麼異常的話可以用父類接收
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- String sNum1 = "10"; //輸入的除數
- String sNum2 = "0"; //輸入的被除數
- try {
- //String轉換爲int類型
- int num1 = Integer.parseInt(sNum1);
- int num2 = Integer.parseInt(sNum2);
- //兩個整數相除
- int ret = num1 / num2; //除數爲0,出現異常
- System.out.println("結果=" + ret);
- } catch (ArithmeticException e) {
- System.out.println("除數爲0");
- } catch (NumberFormatException e) {
- System.out.println("類型轉換異常");
- } catch (Exception e) {
- e.printStackTrace(); //其他異常統一用父類接受也可以
- }
- System.out.println("end------");
- }
- }
或者直接用父類接收全部異常
- public class ExceptionDemo1 {
-
- public static void main(String[] args) {
- System.out.println("begin----");
- String sNum1 = "10"; //輸入的除數
- String sNum2 = "0"; //輸入的被除數
- try {
- //String轉換爲int類型
- int num1 = Integer.parseInt(sNum1);
- int num2 = Integer.parseInt(sNum2);
- //兩個整數相除
- int ret = num1 / num2; //除數爲0,出現異常
- System.out.println("結果=" + ret);
- } catch (Exception e) {
- e.printStackTrace(); //直接用異常父類接收
- }
- System.out.println("end------");
- }
- }
注意:
1:一個catch語句,只能捕獲一種類型的異常,如果需要捕獲多種異常,就得使用多個catch語句.
2:代碼在一瞬間只能出現一種類型的異常,只需要一個catch捕獲,不可能同時出現多個異常.
4.finally代碼塊
finally語句塊表示最終都會執行的代碼,無論有沒有異常.
---------------------------------------------------------------------------------------
什麼時候的代碼必須最終執行:
當我們在try語句塊中打開了一些物理資源(磁盤文件/網絡連接/數據庫連接等),我們都得在使用完之後,最終關閉打開的資源.
---------------------------------------------------------------------------------------
finally的兩種語法:
1):try...finally: 此時沒有catch來捕獲異常,因爲此時根據應用場景,我們會拋出異常,自己不處理.
2):try...catch....finally:自身需要處理異常,最終還得關閉資源.
沒有異常:
- public class ExceptionDemo2 {
-
- public static void main(String[] args) {
- System.out.println("begin....");
- try {
- int ret = 10 / 2;
- } catch (ArithmeticException e) {
- System.out.println("異常:除數爲0");
- } finally {
- System.out.println("關閉資源");
- }
- System.out.println("end.....");
- }
- }
出現異常:
- public class ExceptionDemo2 {
-
- public static void main(String[] args) {
- System.out.println("begin....");
- try {
- int ret = 10 / 0;
- } catch (ArithmeticException e) {
- System.out.println("異常:除數爲0");
- } finally {
- System.out.println("關閉資源");
- }
- System.out.println("end.....");
- }
- }
可以看見,沒有異常或者出現異常之後,程序會處理異常,打印異常信息,然後會進入finally代碼塊執行代碼塊中的內容,無論有沒有異常,finally中的代碼都會執行.
注意:finally不能單獨使用.
---------------------------------------------------------------------------------------
當只有在try或者catch中調用退出JVM的相關方法,此時finally纔不會執行,否則finally永遠會執行.
System.exit(0);//退出JVM
- public public class ExceptionDemo2 {
-
- public static void main(String[] args) {
- System.out.println("begin....");
- try {
- int ret = 10 / 0;
- } catch (ArithmeticException e) {
- System.out.println("異常:除數爲0");
- System.exit(0);//JVM退出
- } finally {
- System.out.println("關閉資源"); //此時不執行
- }