異常-Java學習日記
阿新 • • 發佈:2022-04-06
異常:就是程式不正常的情況
ava中程式的異常:Throwable
Error:嚴重的問題,這樣的情況,我們一般不做處理,因為這樣的問題一般不是程式本身帶來問題,而是外界導致。
Exception:
編譯時期異常:除了RuntimeException以外的異常都是編譯時期異常,這樣的異常必須做處理,
如果不處理程式無法執行,編譯無法通過
執行時期異常:RuntimeException 這樣的 問題我們可以不做處理,因為這是你自己的問題,通常情況下,出現這樣的問題一般都是
因為程式碼的邏輯不夠嚴謹導致的。
出現問題後,如果我們沒有做任何處理,JVM會提供一個預設的處理方式,可以看到出現了什麼異常,出現異常的資訊,以及出現問題的程式碼行
public class ExceptionDemo1 { public static void main(String[] args) { //執行時期異常 int[] arr = {11,22,33,44,55}; System.out.println(arr[1]); System.out.println(arr[5]); System.out.println("hello"); } } /* 執行結果 22 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at com.shujia.lc.day22.ketang.ExceptionDemo1.main(ExceptionDemo1.java:27)*/
異常處理方案
1、try…catch…finally
2、throws
try…catch…finally處理格式:
try{
可能會出現問題的程式碼;
}catch(異常的類名 變數名){
針對出現的問題做處理;
}finally{
一般情況下,這裡寫釋放資源;
}
變形格式:
try{
可能會出現問題的程式碼;
}catch(異常的類名 變數名){
針對出現的問題做處理;
}
注意:
1、try裡面的程式碼如果出現問題,try裡面的程式碼就會停在那一行,然後JVM會自動識別是什麼問題,去catch匹配對應的異常,匹配到後
執行對應的處理方式(catch大括號中的程式碼),如果沒有匹配到,JVM會執行預設的處理方式,而預設的處理方式會將程式停止,後面的程式碼都不會執行
2、try裡面的程式碼越少越好,確定不會出錯的程式碼就不要try裡面寫了。
3、catch裡面必須要有內容,哪怕就寫了一個簡單輸出語句提示
public class ExceptionDemo2 { public static void main(String[] args) { int a = 10; int b = 0; try { System.out.println(a / b); } catch (ArithmeticException ae) { System.out.println("你的除數為0了"); } System.out.println("world"); System.out.println("hello"); } } /* 執行結果 你的除數為0了 world hello */
處理一個異常和處理多個異常
處理多個異常的方案:
1、對每一個異常都寫一個try...catch...
2、寫一個try,多個catch
try{
...
}catch(){
...
}catch(){
...
}
注意事項:
1、多個異常使用try..catch處理的時候,catch可以寫一個,裡面寫最大的父類Exception,但是如果這麼寫了,try裡面
無論出現什麼錯誤,都會匹配到這裡的catch,這樣的做的話,所有的問題處理方式都是一種處理,沒法區分,不推薦這麼做
2、多個catch之間可以是繼承關係,但是,要把父類的catch寫在最後,因為出現問題匹配catch的順序是自上而下的。
3、JDK1.7之後出現了處理異常的新方案:
try{
放上可能會出現問題的程式碼;
}catch(異常類名1|異常類名2|異常類名3|... 變數名){
處理問題的程式碼;
}
注意:
1)新特性處理的方式並不太好,因為多種異常的處理方式統一是一種
2)新特性的處理catch中的異常只能是平級關係,不能是繼承關係
public class ExceptionDemo3 { public static void main(String[] args) { //編譯時期異常 String s = "2022-04-06 14:35:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // try { // Date date = sdf.parse(s); // System.out.println(date); // }catch (ParseException pe){ // System.out.println("日期轉換出錯了!!!"); // } // // int[] arr = {11,22,33,44,55}; // try { // System.out.println(arr[5]); // }catch (ArrayIndexOutOfBoundsException aiob){ // System.out.println("取了不該取的索引"); // } System.out.println("==============================================="); //第二種處理方式:寫一個try,多個catch // try { // Date date = sdf.parse(s); // int[] arr = {11, 22, 33, 44, 55}; // System.out.println(arr[5]); // }catch (ParseException ae){ // System.out.println("日期處理格式"); // }catch (Exception ae){ // System.out.println("取了不該取的索引"); // } System.out.println("==============================================="); //JDK1.7try..catch處理新方式 try { Date date = sdf.parse(s); int[] arr = {11, 22, 33, 44, 55}; System.out.println(arr[5]); }catch (ParseException|ArrayIndexOutOfBoundsException e){ System.out.println("出錯啦!!"); } System.out.println("你好!!!"); } }
在前面案例中,我們處理異常的方式都是輸出一句話,告訴我們出了什麼問題,但是呢,對比發現,並沒有預設處理方式來的直接和清楚
try..catch..的處理過程是,當try中的程式碼出現了問題的時候,JVM會幫助我們生成一個異常物件,然後把這個物件跑出來,與catch中的
型別進行匹配,如果匹配到了,就走對應的處理方式。
異常中需要了解的幾個方法:
1、getMessage()
獲取異常資訊,返回字串。
2、toString()
獲取異常類名和異常資訊,返回字串。
3、printStackTrace()
獲取異常類名和異常資訊,以及異常出現在程式中的位置。返回值void
public class ExceptionDemo4 { public static void main(String[] args) { String s = "2020-04-06"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // try { // Date date = sdf.parse(s); // System.out.println(date); // }catch (ParseException pe){ // ParseException pe = new ParseException(); //// System.out.println("日期轉換異常"); //// String message = pe.getMessage(); //// System.out.println(message); // //// String s1 = pe.toString(); //// //此物件的類的name(全路徑名) //// //": "(冒號和一個空格) //// //呼叫此物件中的getLocalizedMessage()方法,底層呼叫的還是getMessage()方法。 //// System.out.println(s1); // // pe.printStackTrace(); // } try { Date date = sdf.parse(s); } catch (ParseException e) { e.printStackTrace(); } System.out.println("你好!!"); } }
有些時候,我們可以對異常去做處理,但是呢,有些時候,我們根本就沒有許可權去處理這些異常。
或者說, 我們處理不了,就不處理了,交給更高許可權的去處理。
為了解決這樣出錯的問題,Java針對這種情況,就提供了另一種處理方案:丟擲
格式:
throws 異常類名
注意:這個格式必須跟在方法的小括號後面,大括號前面。
注意:
1、儘量不要在main方法上面丟擲,因為main方法是由JVM呼叫的,如果出問題了,依舊是走預設的處理方式,
而預設的處理方式,會將程式終止,後續程式碼不會執行,推薦能try..catch就try..catch
(為了上課方便,後面的課程我就大部分在方法上丟擲了)
2、編譯時期異常丟擲,呼叫者必須要做處理,因為不做就沒辦法通過編譯,就無法執行
3、執行時期異常丟擲,呼叫者可以不做處理,但是執行出了問題,程式終止,後續程式碼不會執行
(推薦執行前檢查程式碼邏輯,其次可以像處理編譯時期異常一樣try..catch)
throw: 在方法內部丟擲,後面跟上具體的異常物件
(面試題:throw與throws的區別)}
throws:
用在方法的聲明後面,後面跟的是異常的類名
異常的類名可以是多個,多個類名之間使用逗號隔開
表示將異常丟擲,交給呼叫者去處理
throws表示的是一種可能性,並不一定會發生這些異常
throw:
用在方法的內部,後面跟的是異常的物件;
只能是一個物件,不能丟擲多個
表示丟擲異常,由方法內部的語句體去做處理
throw表示的是方法內部一定會出現某種異常,是確定的。
public class ExceptionDemo5 { public static void main(String[] args) { try { function(); } catch (ParseException e) { e.printStackTrace(); }catch (ArithmeticException ae){ ae.printStackTrace(); } // function(); // function2(); // try { // function3(); // }catch (ArithmeticException ae){ // ae.printStackTrace(); // } System.out.println("你好!!!"); } public static void function3() { int a = 10; // int b = 2; int b = 0; if (b != 0) { System.out.println(a/b); }else { System.out.println("除數為0"); //在方法內部丟擲,丟擲的是一個具體的物件,表示一定會出現這樣的問題 throw new ArithmeticException(); } } public static void function2() throws ArithmeticException { int a = 10; // int b = 2; int b = 0; // if(b!=0){ // System.out.println(a/b); // }else { // System.out.println("除數為0"); // } // try { // System.out.println(a/b); // }catch (ArithmeticException ae){ // ae.printStackTrace(); // } System.out.println(a / b); } public static void function() throws ParseException,ArithmeticException { String s = "2020-04-06 16:08:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = sdf.parse(s); int a = 10; int b = 0; System.out.println(a / b); } }
處理異常的格式:
1、try...catch...
2、try...catch...catch
3、try...catch...catch...finally
4、try...catch..finally
注意:
1、無論try裡面的程式碼會不會報錯,都會執行finally中的語句
特殊情況:在執行finally之前,程式就已經退出
public class ExceptionDemo6 { public static void main(String[] args) { String s = "2020-04-06 16:45:00"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date date = sdf.parse(s); System.exit(0); //這個語句就是結束程式執行 } catch (ParseException e) { e.printStackTrace(); } finally { //通常情況下,這裡面放的是釋放資源的程式碼 System.out.println("這是finally中的語句"); } System.out.println("你好!!"); } }
如果方法中有try..catch..finally,並且,在catch中有return語句,結果會是什麼樣子呢?
在finally之前執行還是在finally之後執行呢?在finally執行中間
面試題:finally,final,finalize他們三個你認識嗎,他們什麼什麼區別?
回答:都認識,但是他們三個之間沒有任何關係,只是長得像罷了。finally是在異常處理中遇到,一般是用於釋放資源的
final是java中的一個關鍵字,他可以修飾類,成員變數,成員方法,修飾類,類不能被繼承,修飾成員變數,
變數變常量,修飾成員方法,方法不能被重寫;finalize是Object類中的一個方法名,該方法是用於垃圾回收的
但是什麼時候回收不確定。
public class ExceptionDemo7 { public static void main(String[] args) { System.out.println(fun()); // a = } public static int fun(){ int a = 20; int b = 0; try { a = 30; System.out.println(a/b); a = 40; // 這一行肯定不會執行 }catch (ArithmeticException ae){ a = 60; // ae.printStackTrace(); return a; //當程式走到這裡的時候,方法其實已經有了一個返回值路徑,返回的就是60。 //但是程式此刻還沒有結束,所以依舊會走finally中的語句 }finally { a = 50; System.out.println(a); // return a; } return a; // 這裡其實是為了語法的正確,加了return } }
異常在繼承關係中的使用:
1、子類重寫父類方法時,子類的方法必須丟擲相同的異常或父類異常的子類。(父親壞了,兒子不能比父親更壞)
2、如果父類丟擲了多個異常,子類重寫父類時,只能丟擲相同的異常或者是他的子集,子類不能丟擲父類沒有的異常
3、如果被重寫的方法沒有異常丟擲,那麼子類的方法絕對不可以丟擲異常,如果子類方法內有異常發生,
那麼子類只能try,不能throws