Java進(jìn)階---異常處理

異常的概念

異常是程序中的一些錯誤,但并不是所有的錯誤都是異常,并且錯誤有時候是可以避免的。

比如說,你的代碼少了一個分號,那么運(yùn)行出來結(jié)果是提示是錯誤java.lang.Error;如果你用System.out.println(11/0),那么你是因?yàn)槟阌?做了除數(shù),會拋出java.lang.ArithmeticException的異常。

異常的分類

檢查性異常:最具代表的檢查性異常是用戶錯誤或問題引起的異常,這是程序員無法預(yù)見的。例如要打開一個不存在文件時,一個異常就發(fā)生了,這些異常在編譯時不能被簡單地忽略。
運(yùn)行時異常: 運(yùn)行時異常是可能被程序員避免的異常。與檢查性異常相反,運(yùn)行時異??梢栽诰幾g時被忽略。
錯誤: 錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。例如,當(dāng)棧溢出時,一個錯誤就發(fā)生了,它們在編譯也檢查不到的。

異常體系

異常.png

Java處理異常的方法

方法1:捕獲異常(try-catch)

當(dāng)拋出一個異常時,可以在try-catch塊中捕獲它并進(jìn)行處理。
捕獲異常的格式

try{
可能發(fā)生異常的代碼塊
}catch(可以捕獲的異常1){
處理異常1的代碼
}catch(可以捕獲的異常2){
處理異常2的代碼
}finally{
處理完所有異常后一定會執(zhí)行的代碼。
在這里注意的事。如果在這里沒有出現(xiàn)異常,最終也會執(zhí)行這行代碼
}

實(shí)例:

public class Exception1 {
    public static void main(String[] args) {
        
        //方法1:捕獲異常
        int a = 0;
        int b = 20;
        FileReader fr = null;
        try {
            int c = b/a;
        }catch (ArithmeticException e){
            System.out.println(e.getMessage());
        } 
    }
}

在上面的代碼中,由于a的值為0,不能當(dāng)分母,所以就會拋出一個"ArithmeticException"異常,在這里我們使用try-catch語塊來處理異常,會在控制臺輸出相關(guān)異常信息。
若執(zhí)行try塊的過程中沒有發(fā)生異常,則跳過catch子句。若是出現(xiàn)異常,try塊中剩余語句不再執(zhí)行。開始逐步檢查catch塊,判斷catch塊的異常類實(shí)例是否是捕獲的異常類型。匹配后執(zhí)行相應(yīng)的catch塊中的代碼。如果異常沒有在當(dāng)前的方法中被捕獲,就會被傳遞給該方法的調(diào)用者。這個過程一直重復(fù),直到異常被捕獲或被傳給main方法(交給JVM來捕獲)。

捕獲異常的順序

一個通用父類可以派生出各種異常類,如果一個catch塊可以捕獲一個父類的異常對象,它就能捕獲那個父類的所有子類的異常對象。如果捕獲的是多個同類型異常,則子類異常在前,父類異常在后,不然會導(dǎo)致編譯錯誤。這是因?yàn)楦割惍惓D依俗宇惍惓?,如果父類異常在前,子類異常永遠(yuǎn)捕獲不到,導(dǎo)致有時候無法準(zhǔn)確描述錯誤信息。

try {
            File f =new File("C:\\ProgramFile\\test.txt");
            FileInputStream fis = new FileInputStream(f);
        } catch (FileNotFoundException e) { //子類異常
            e.printStackTrace();
        } catch(IOException ie) {  //父類異常
            ie.printStackTrace();
        } catch(Exception e) { //基類運(yùn)行時異常
            e.printStackTrace();
        }

方法2:拋出異常(throw)

如果代碼可能會引發(fā)某種錯誤,可以創(chuàng)建一個合適的異常類實(shí)例并拋出它,這就是拋出異常。如下所示:

public class Exception1 {
    public static void main(String[] args) {
/**方法2的調(diào)用*/
        try {
            TException.test();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
/**方法2:使用throws拋出異常 如果有多個異常可以用逗號隔開,或者異常太多,可以直接拋出Exception*/
class TException {
    public static void test() throws FileNotFoundException {
        FileReader fr = new FileReader("");
    }
    public static void test3()throws PXDException{
        //.....
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        StackTraceElement e =stackTrace[2];
        String detail = e.getFileName()+"->"+e.getMethodName()+"->"+e.getLineNumber();
        throw new LJRException("自己的異常類:無所作為"+detail);
    }
}

自定義異常

/**自定義異常 1.提供一個有參數(shù)構(gòu)造方法和一個無參數(shù)的構(gòu)造方法*/
class LJRException extends Exception{
    public LJRException(){

    }
    public LJRException(String s){
        super(s);
    }
}

說明:

/**
 * 異常處理 錯誤:error
 *
 * 處理運(yùn)行過程中出現(xiàn)的不可控的錯誤 使程序更健壯
 * try{執(zhí)行的代碼 可能出現(xiàn)的異常 一旦出現(xiàn)異常,系統(tǒng)自動為我們創(chuàng)建一個異常對象 并拋出}
 * catch(異常的類型 e){如果需要自己處理就catch}
 * **如果有多個異常 就使用多個catch來捕獲異常
 * **如果有多個異常 catch的順序是從小到大
 * **如果異常出現(xiàn),在try代碼塊里后面的代碼將不會執(zhí)行
 * 當(dāng)特殊情況出現(xiàn)了,自己可以選擇拋出異常
 */

注意:

1.try、catch和finally都不能單獨(dú)使用,只能是try-catch、try-finally或者try-catch-finally。
2.try語句塊監(jiān)控代碼,出現(xiàn)異常就停止執(zhí)行下面的代碼,然后將異常移交給catch語句塊來處理。
3.finally語句塊中的代碼一定會被執(zhí)行,常用于回收資源 。
4.throws:聲明一個異常,告知方法調(diào)用者。
5.throw :拋出一個異常,至于該異常被捕獲還是繼續(xù)拋出都與它無關(guān)。

異常相關(guān)面試題

1、try{} 里有一個 return 語句,那么緊跟在這個 try 后的 finally{} 里的 code 會不會被執(zhí)行,什么時候被執(zhí)行,在 return 前還是后?

答案:會執(zhí)行,在方法返回調(diào)用者前執(zhí)行。

2、Java語言如何進(jìn)行異常處理,關(guān)鍵字:throws、throw、try、catch、finally分別如何使用?

答:Java通過面向?qū)ο蟮姆椒ㄟM(jìn)行異常處理,把各種不同的異常進(jìn)行分類,并提供了良好的接口。在Java中,每個異常都是一個對象,它是Throwable類或其子類的實(shí)例。當(dāng)一個方法出現(xiàn)異常后便拋出一個異常對象,該對象中包含有異常信息,調(diào)用這個對象的方法可以捕獲到這個異常并可以對其進(jìn)行處理。Java的異常處理是通過5個關(guān)鍵詞來實(shí)現(xiàn)的:try、catch、throw、throws和finally。一般情況下是用try來執(zhí)行一段程序,如果系統(tǒng)會拋出(throw)一個異常對象,可以通過它的類型來捕獲(catch)它,或通過總是執(zhí)行代碼塊(finally)來處理;try用來指定一塊預(yù)防所有異常的程序;catch子句緊跟在try塊后面,用來指定你想要捕獲的異常的類型;throw語句用來明確地拋出一個異常;throws用來聲明一個方法可能拋出的各種異常(當(dāng)然聲明異常時允許無病呻吟);finally為確保一段代碼不管發(fā)生什么異常狀況都要被執(zhí)行;try語句可以嵌套,每當(dāng)遇到一個try語句,異常的結(jié)構(gòu)就會被放入異常棧中,直到所有的try語句都完成。如果下一級的try語句沒有對某種異常進(jìn)行處理,異常棧就會執(zhí)行出棧操作,直到遇到有處理這種異常的try語句或者最終將異常拋給JVM。

3、運(yùn)行時異常與受檢異常有何異同?

答:異常表示程序運(yùn)行過程中可能出現(xiàn)的非正常狀態(tài),運(yùn)行時異常表示虛擬機(jī)的通常操作中可能遇到的異常,是一種常見運(yùn)行錯誤,只要程序設(shè)計(jì)得沒有問題通常就不會發(fā)生。受檢異常跟程序運(yùn)行的上下文環(huán)境有關(guān),即使程序設(shè)計(jì)無誤,仍然可能因使用的問題而引發(fā)。Java編譯器要求方法必須聲明拋出可能發(fā)生的受檢異常,但是并不要求必須聲明拋出未被捕獲的運(yùn)行時異常。異常和繼承一樣,是面向?qū)ο蟪绦蛟O(shè)計(jì)中經(jīng)常被濫用的東西,在Effective Java中對異常的使用給出了以下指導(dǎo)原則:

  • 不要將異常處理用于正常的控制流(設(shè)計(jì)良好的API不應(yīng)該強(qiáng)迫它的調(diào)用者為了正常的控制流而使用異常)
  • 對可以恢復(fù)的情況使用受檢異常,對編程錯誤使用運(yùn)行時異常
  • 避免不必要的使用受檢異常(可以通過一些狀態(tài)檢測手段來避免異常的發(fā)生)
  • 優(yōu)先使用標(biāo)準(zhǔn)的異常
  • 每個方法拋出的異常都要有文檔
  • 保持異常的原子性
  • 不要在catch中忽略掉捕獲到的異常
4、列出一些你常見的運(yùn)行時異常?

答:

  • ArithmeticException(算術(shù)異常)
  • ClassCastException (類轉(zhuǎn)換異常)
  • IllegalArgumentException (非法參數(shù)異常)
  • IndexOutOfBoundsException (下標(biāo)越界異常)
  • NullPointerException (空指針異常)
5.try-catch-finally-return執(zhí)行順序?

1.不管是否有異常產(chǎn)生,finally塊中代碼都會執(zhí)行
2.當(dāng)try和catch中有return語句時,finally塊仍然會執(zhí)行
3.finally是在return后面的表達(dá)式運(yùn)算執(zhí)行的,所以函數(shù)返回值在finally執(zhí)行前確定的,無論finally中的代碼怎么樣,返回的值都不會改變,仍然是之前return語句中保存的值
4.finally中最好不要包含return,否則程序會提前退出,返回值不是try或catch中保存的返回值

6.Java異常類的重要方法是什么?

1.異常及其所有子類不提供任何特定方法,并且所有方法都在基類Throwable中定義。
2.String getMessage():此方法返回消息String of Throwable,并且可以在通過構(gòu)造函數(shù)創(chuàng)建異常時提供消息。
3.String getLocalizedMessage():提供此方法,以便子類可以覆蓋它以向調(diào)用程序提供特定于語言環(huán)境的消息。此方法getMessage()的可拋出類實(shí)現(xiàn)只是使用方法來返回異常消息。
4.synchronized Throwable getCause() :此方法返回異常的原因或null id,原因未知。
5.String toString():此方法以String格式返回有關(guān)Throwable的信息,返回的String包含Throwable類和本地化消息的名稱。
6void printStackTrace() :此方法將堆棧跟蹤信息打印到標(biāo)準(zhǔn)錯誤流,此方法已重載,我們可以將PrintStream或PrintWriter作為參數(shù)傳遞,以將堆棧跟蹤信息寫入文件或流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容