Java學習筆記--異常處理(傳智播客的總結)
背景:
我們的java程式也是會存在某些不正常 的情況的,這些不正常的 情況我們就統稱異常。(還有一種是IO流的異常 要包裝成執行時異常)
異常體系:
———-| Throwable 所以異常或者錯誤類的超類
————–|Error 錯誤 錯誤一般是用於jvm或者是硬體引發的問題,所以我們一般不會通過程式碼去處理錯誤的。
————–|Exception 異常 是需要通過程式碼去處理的。
如何區分錯誤與異常呢:
如果程式出現了不正常的資訊,如果不正常的資訊的類名是以Error結尾的,那麼肯定是一個錯誤。
如果是以Exception結尾的,那麼肯定就是一個異常。
Throwable常用的方法:
toString() 返回當前異常物件的完整類名+病態資訊。 包名+類名 = 完整類名
getMessage() 返回的是建立Throwable傳入的字串資訊。
printStackTrace() 列印異常的棧資訊
比如:虛擬機器能分配的記憶體是50多mb如果超過了就是Error型別的
疑問: 下面的資訊是通過printStackTrace方法打印出來,那麼異常物件從何而來呢?
Exception in thread “main” java.lang.ArithmeticException: / by zero
at Demo10.div(Demo10.java:10)
at Demo10.main(Demo10.java:5)
jvm執行到a/b這個語句的時候,發現b為0,除數為0在我們現實生活中是屬於
不正常的情況,jvm一旦發現了這種不正常的情況時候,那麼jvm就會馬上建立
一個對應的異常物件,並且會呼叫這個異常物件 的printStackTrace的方法來處理。
異常的處理:
方式一:捕獲處理
捕獲處理的格式:
try{
可能發生異常的程式碼;
}catch(捕獲的異常型別 變數名){
處理異常的程式碼....
}
捕獲處理要注意的細節:
- 如果try塊中程式碼出了異常經過了處理之後,那麼try-catch塊外面的程式碼可以正常執行。
- 如果try塊中出了異常的程式碼,那麼在try塊中出現異常程式碼後面的程式碼是不會執行了。
- 一個try塊後面是可以跟有多個catch塊的,也就是一個try塊可以捕獲多種異常的型別。
- 一個try塊可以捕獲多種異常的型別,但是捕獲的異常型別必須從小到大進行捕獲,否則編譯報錯。
疑問一 : 異常的處理感覺沒有多大作用,因為都是輸出一個話而已?
異常處理非常有用,只不過是由於我們目前所接觸的知識點太過於侷限而已。
疑問二: 以後捕獲處理 的時候是否就是捕獲Exception即可?
錯的,因為我們在現實開發中遇到不同的異常型別的時候,我往往會有不同 的處理方式。
所以要分開不同的異常型別處理。
注意 如果丟擲了一個異常 那麼接下來的程式碼就不會執行
*/
舉例:
try catch方法
class A{
public static void main(String[] args){
div(1,0);
}
public static void div(int a,int b){
int c=0;
try{
c=a/b;
}catch(ArithmeticException e){
System.out.println("1");
}catch(NullPointerException e){
System.out.println("2");
}catch(Exception e){
System.out.println("3");
}
}
}
/*
異常的處理方式----丟擲處理
丟擲處理(throw throws)
丟擲處理要注意的細節:
1. 如果一個方法的內部丟擲了一個異常 物件,那麼必須要在方法上宣告丟擲。
2. 如果呼叫了一個宣告丟擲異常 的方法,那麼呼叫者必須要處理異常。
3. 如果一個方法內部丟擲了一個異常物件,那麼throw語句後面的程式碼都不會再執行了(一個方法遇到了throw關鍵字,該方法也會馬上停止執行的)。
4. 在一種情況下,只能丟擲一種型別異常物件。
throw 與throws兩個關鍵字:
1. throw關鍵字是用於方法內部的,throws是用於方法聲宣告上的。
2. throw關鍵字是用於方法內部丟擲一個異常物件的,throws關鍵字是用於在方法宣告上宣告丟擲異常型別的。
3. throw關鍵字後面只能有一個異常物件,throws後面一次可以宣告丟擲多種型別的 異常。
疑問:何時使用丟擲處理?何時捕獲處理?原則是如何?
如果你需要通知到呼叫者,你程式碼出了問題,那麼這時候就使用丟擲處理.
如果程式碼是直接與使用者打交道遇到了異常千萬不要再拋,再拋的話,就給了使用者了。
這時候就應該使用捕獲處理。
*/
舉例:throw 丟擲
class Demo2{
public static void main(String[] args)throws Exception{
try{
div(0,1,null);
}catch(Exception e){
System.out.print("1");
throw new Exception();
}
}
public static void div(int i,int j,int[] arr) throws Exception{
if(i==0){
throw new Exception();
}else if(arr==null){
throw new NullPointerException();
}
int c=i/j;
System.out.println(c);
}
}
如果 main函式也丟擲異常 那麼到時候出錯的時候直接列印printStackTrace
自定義異常類:
/*
sun提供了很多的異常類給我們用於描述程式中各種的不正常情況,但是sun 給我
提供異常類還不足以描述我們現實生活中所有不正常情況,那麼這時候我們就需要
自定義異常類。
需求: 模擬feiQ上線的時候,如果沒有插上網線,那麼就丟擲一個沒有插上網線的異常,
如果已經插上了網上,那麼就正常顯示好友列表。
自定義異常類的步驟: 自定義一個類繼承Exception即可。
class NullIpException extends Exception{
public NullIpException(String x){
super(x);
}
}
class Demo2{
public static void main(String[] args){
String ip="sdf";
ip=null;
try{
xx(ip);
}catch(Exception z){
z.printStackTrace();
}
}
public static void xx(String ip)throws Exception{
if(ip==null){
throw new NullIpException("noip");
}
System.out.println("sdfsadfasdfas");
}
}
—————| 執行時異常: 如果一個方法內部丟擲了一個執行時異常,那麼方法上 可以宣告也可以不 宣告,呼叫者可以以處理也可以不處理。
——————| 編譯時異常(非執行時異常、受檢異常): 如果一個方法內部丟擲了一個編譯時異常物件,那麼方法上就必須要宣告,而且呼叫者也必須要處理。
執行時異常: RuntimeException以及RuntimeException子類 都是屬於執行時異常。
編譯時異常: 除了執行時異常就是編譯異常。
疑問: 為什麼java編譯器會如此嚴格要求編譯時異常,對執行時異常如此寬鬆?
執行時異常都是可以通過程式設計師良好的程式設計習慣去避免,所以java編譯器就沒有嚴格要求處理執行時異常。
————————————————————————————————————
*/
finally塊的 使用前提是必須要存在try塊才能使用。
finally塊的程式碼在任何情況下都會執行的,除了j
vm退出的情況。
finally非常適合做資源釋放的工作,這樣子可以保證資原始檔在任何情況下都 會被釋放。
finally:
結論:
1、不管有木有出現異常,finally塊中程式碼都會執行;
2、當try和catch中有return時,finally仍然會執行;
3、finally是在return後面的表示式運算後執行的(此時並沒有返回運算後的值,而是先把要返回的值儲存起來,管finally中的程式碼怎麼樣,返回的值都不會改變,任然是之前儲存的值),所以函式返回值是在finally執行前確定的;
4、finally中最好不要包含return,否則程式會提前退出,返回值不是try或catch中儲存的返回值。
System.exit(0);//退出jvm 那麼finally是不會執行的
舉例:
class Demo2{
public static void main(String[] args){
try{
div(1);
}catch(Exception e){
e.printStackTrace();
System.out.println("xipanzi");
}
}
public static void div(int n) throws Exception{
try{
System.exit(0);
}catch(Exception e){
System.out.print("sdf");
}finally{
System.out.print("finally");
}
}
}
如果try裡面是return 那麼也會執行finally 但是不會影響return的返回值
因為finally是在return之後才執行的
fianlly釋放資源的程式碼
import java.io.*;
class Demo6
{
public static void main(String[] args) throws Exception
{
FileReader fileReader = null;
try{
//找到目標檔案
File file = new File("f:\\a.txt");
//建立程式與檔案的資料通道
fileReader = new FileReader(file);
//讀取檔案
char[] buf = new char[1024];
int length = 0;
length = fileReader.read(buf);
System.out.println("讀取到的內容:"+ new String(buf,0,length));
}catch(IOException e){
System.out.println("讀取資原始檔失敗....");
}finally{
try{
//關閉資源
fileReader.close();
System.out.println("釋放資原始檔成功....");
}catch(IOException e){
System.out.println("釋放資原始檔失敗....");
}
}
}
}
總結:
1:子類覆蓋父類方法是,父類方法丟擲異常,子類的覆蓋方法可以不拋
出異常,或者丟擲父類方法的異常,或者該父類方法異常的子類。
2:父類方法丟擲了多個異常,子類覆蓋方法時,只能丟擲父類異常的子
集
3:父類沒有丟擲異常子類不可丟擲異常
1:子類發生非執行時異常,需要進行try{}catch的(){}處理,不能
丟擲。
4:子類不能比父類丟擲更多的異常