1. 程式人生 > >Java學習筆記--異常處理(傳智播客的總結)

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(捕獲的異常型別 變數名){
            處理異常的程式碼....
        }

捕獲處理要注意的細節:

  1. 如果try塊中程式碼出了異常經過了處理之後,那麼try-catch塊外面的程式碼可以正常執行。
  2. 如果try塊中出了異常的程式碼,那麼在try塊中出現異常程式碼後面的程式碼是不會執行了。
  3. 一個try塊後面是可以跟有多個catch塊的,也就是一個try塊可以捕獲多種異常的型別。
  4. 一個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:子類不能比父類丟擲更多的異常