溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java的異常與處理機(jī)制分析【附面試題】

發(fā)布時(shí)間:2020-10-15 15:20:22 來源:腳本之家 閱讀:154 作者:XINGKONG_04 欄目:編程語言

本文實(shí)例講述了java的異常與處理機(jī)制。分享給大家供大家參考,具體如下:

java的異常機(jī)制

Throwable類

Throwable類是Java異常類型的頂層父類,一個(gè)對象只有是 Throwable 類的(直接或者間接)實(shí)例,他才是一個(gè)異常對象,才能被異常處理機(jī)制識(shí)別。JDK中內(nèi)建了一些常用的異常類,我們也可以自定義異常。

Throwable又派生出Error類和Exception類。

錯(cuò)誤:Error類以及他的子類的實(shí)例,代表了JVM本身的錯(cuò)誤。錯(cuò)誤不能被程序員通過代碼處理,Error很少出現(xiàn)。因此,程序員應(yīng)該關(guān)注Exception為父類的分支下的各種異常類。

異常:Exception以及他的子類,代表程序運(yùn)行時(shí)發(fā)送的各種不期望發(fā)生的事件。可以被Java異常處理機(jī)制使用,是異常處理的核心。

java異常體系結(jié)構(gòu)

java的異常與處理機(jī)制分析【附面試題】

Java中的異常分為兩大類(根據(jù)javac對異常的處理要求):

Checked exception(受檢異常):除了Error 和 RuntimeException的其它異常。受檢異常表示程序本身沒有問題,但由于I/O、網(wǎng)絡(luò)、數(shù)據(jù)庫等其他不可預(yù)測的錯(cuò)誤導(dǎo)致的異常,也可能是因?yàn)橘Y源耗盡導(dǎo)致的異常。javac強(qiáng)制要求程序員為這樣的異常做預(yù)備處理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch語句捕獲它并處理,要么用throws子句聲明拋出它,否則編譯不會(huì)通過。這樣的異常一般是由程序的運(yùn)行環(huán)境導(dǎo)致的。因?yàn)槌绦蚩赡鼙贿\(yùn)行在各種未知的環(huán)境下,而程序員無法干預(yù)用戶如何使用他編寫的程序,于是程序員就應(yīng)該為這樣的異常時(shí)刻準(zhǔn)備著。如SQLException , IOException,ClassNotFoundException 等。

Unchecked exception(Runtime Exception)(未受檢異常):Error 和 RuntimeException 以及他們的子類。未受檢異常一般認(rèn)為是代碼的邏輯問題,一般需要修改代碼來解決異常,也可以使用異常機(jī)制處理。這樣的異常發(fā)生的原因多半是代碼寫的有問題。如除0錯(cuò)誤ArithmeticException,錯(cuò)誤的強(qiáng)制類型轉(zhuǎn)換錯(cuò)誤ClassCastException,數(shù)組索引越界ArrayIndexOutOfBoundsException,使用了空對象NullPointerException等等。

Runtime Exception類直接繼承自Exception類,Java中所有的運(yùn)行時(shí)異常都會(huì)直接或間接地繼承自Runtime Exception

Java中凡是繼承自Exception,而不是繼承自Runtime Exception類的異常都是Checked Exception

異常處理的基本語法

在編寫代碼處理異常時(shí),對于檢查異常,有2種不同的處理方式:使用try…catch…finally語句塊處理它?;蛘撸诤瘮?shù)簽名中使用throws 聲明交給函數(shù)調(diào)用者caller去解決。

(1)try…catch…finally語句塊

try{
   //try塊中放可能發(fā)生異常的代碼。
   //如果執(zhí)行完try且不發(fā)生異常,則接著去執(zhí)行finally塊和finally后面的代碼(如果有的話)。
   //如果發(fā)生異常,則嘗試去匹配catch塊。
}catch(SQLException SQLexception){
  //每一個(gè)catch塊用于捕獲并處理一個(gè)特定的異常,或者這異常類型的子類。Java7中可以將多個(gè)異常聲明在一個(gè)catch中。
  //catch后面的括號(hào)定義了異常類型和異常參數(shù)。如果異常與之匹配且是最先匹配到的,則虛擬機(jī)將使用這個(gè)catch塊來處理異常。
  //在catch塊中可以使用這個(gè)塊的異常參數(shù)來獲取異常的相關(guān)信息。異常參數(shù)是這個(gè)catch塊中的局部變量,其它塊不能訪問。
  //如果當(dāng)前try塊中發(fā)生的異常在后續(xù)的所有catch中都沒捕獲到,則先去執(zhí)行finally,然后到這個(gè)函數(shù)的外部caller中去匹配異常處理器。
  //如果try中沒有發(fā)生異常,則所有的catch塊將被忽略。
}catch(Exception exception){
  //...
}finally{
  //finally塊通常是可選的。
  //無論異常是否發(fā)生,異常是否匹配被處理,finally都會(huì)執(zhí)行。
  //一個(gè)try至少要有一個(gè)catch塊,否則, 至少要有1個(gè)finally塊。但是finally不是用來處理異常的,finally不會(huì)捕獲異常。
//如果在try或者catch語句中存在return語句,則return語句會(huì)在finally語句執(zhí)行結(jié)束后執(zhí)行,但是finally并不能改變返回值。
//如果在finally語句中也有return,那么try和catch中的return語句會(huì)丟失,實(shí)際會(huì)返回finally中的返回值。
 //finally主要做一些清理工作,如流的關(guān)閉,數(shù)據(jù)庫連接的關(guān)閉等。
}

注意點(diǎn):

try塊中的局部變量和catch塊中的局部變量(包括異常變量),以及finally中的局部變量,他們之間不可共享使用。

每一個(gè)catch塊用于處理一個(gè)異常。異常匹配是按照catch塊的順序從上往下尋找的,只有第一個(gè)匹配的catch會(huì)得到執(zhí)行。匹配時(shí),不僅運(yùn)行精確匹配,也支持父類匹配,因此,如果同一個(gè)try塊下的多個(gè)catch異常類型有父子關(guān)系,應(yīng)該將子類異常放在前面,父類異常放在后面,這樣保證每個(gè)catch塊都有存在的意義。

finally塊不管異常是否發(fā)生,只要對應(yīng)的try執(zhí)行了,則它一定也執(zhí)行。只有一種方法讓finally塊不執(zhí)行:System.exit()。因此finally塊通常用來做資源釋放操作:關(guān)閉文件,關(guān)閉數(shù)據(jù)庫連接等等。良好的編程習(xí)慣是:在try塊中打開資源,在finally塊中清理釋放這些資源。

finally塊沒有處理異常的能力。處理異常的只能是catch塊。

在同一try…catch…finally塊中 ,如果try中拋出異常,且有匹配的catch塊,則先執(zhí)行catch塊,再執(zhí)行finally塊。如果沒有catch塊匹配,則先執(zhí)行finally,然后去外面的調(diào)用者中尋找合適的catch塊。

在同一try…catch…finally塊中 ,try發(fā)生異常,且匹配的catch塊中處理異常時(shí)也拋出異常,那么后面的finally也會(huì)執(zhí)行:首先執(zhí)行finally塊,然后去外圍調(diào)用者中尋找合適的catch塊。

(2)throws 函數(shù)聲明

throws聲明:如果一個(gè)方法內(nèi)部的代碼會(huì)拋出檢查異常(checked exception),而方法自己又沒有完全處理掉,則javac保證你必須在方法的簽名上使用throws關(guān)鍵字聲明這些可能拋出的異常,否則編譯不通過。

throws是另一種處理異常的方式,它不同于try…catch…finally,throws僅僅是將函數(shù)中可能出現(xiàn)的異常向調(diào)用者聲明,而自己則不具體處理。

采取這種異常處理的原因可能是:方法本身不知道如何處理這樣的異常,或者說讓調(diào)用者處理更好,調(diào)用者需要為可能發(fā)生的異常負(fù)責(zé)。

public void foo() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
{
   //foo內(nèi)部可以拋出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 類的異常,或者他們的子類的異常對象。
}

throw 異常拋出語句

語法 : throw exceptionObject

程序員也可以通過throw語句手動(dòng)顯式的拋出一個(gè)異常。throw語句的后面必須是一個(gè)異常對象。

在某個(gè)方法(如:a方法)中,使用throw new 異常,的方式拋出異常異常,即本方法不會(huì)對異常進(jìn)行處理,而是由調(diào)用a 的方法b來處理(此時(shí)b會(huì)使用throws關(guān)鍵字拋出),如果b也被方法c調(diào)用,那么c來處理,逐層類推,直到main方法,如果main方法也是選擇拋出異常,那么就叫交給JVM處理

throw 語句必須寫在函數(shù)中,執(zhí)行throw 語句的地方就是一個(gè)異常拋出點(diǎn),它和由JRE自動(dòng)形成的異常拋出點(diǎn)沒有任何差別。

package practice;
public class ExceptionTest {
    public static void test(Object obj) {
        try {
            if (obj == null) {
                throw new Exception();// 此處拋出的異常,在catch中被處理了
            }
        } catch (Exception e) {
            System.out.println("nullpoint");
        }
    }
    public static void test2(Object obj) throws Exception {
        try {
            obj.toString();
        } catch (Exception e) {
            throw new Exception();//在catch塊中拋出新的異常,構(gòu)成了異常鏈,這是因?yàn)樵瓉淼漠惓ο骵可能不能處理這個(gè)異常,需要另一個(gè)異常對象來處理該異常
        }
    }
    public static void test1(Object obj) throws Exception {
        if (obj == null) {
            throw new Exception();// 此處拋出的異常,通過throws的方式,由調(diào)用test的方法處理
        }
    }
    public static void main(String[] args) throws Exception{
        ExceptionTest.test(null);
        //處理拋出異常的兩種方式
        //方式一:test2函數(shù)使用throws拋出了異常,所以得接住這個(gè)異常,并處理
        try {
            ExceptionTest.test2(null);
        }catch(Exception e) {
            System.out.println("nullpoint");
        }
        //方式二:test1拋出的異常使用Throws的方式處理
        ExceptionTest.test1(null);
    }
}

自定義異常

自定義異常:通常就是定義了一個(gè)繼承自Exception類的子類,那么這個(gè)類就是一個(gè)自定義異常類。通常情況下,我們都會(huì)直接繼承自Exception類,一般不會(huì)繼承某個(gè)運(yùn)行時(shí)的異常類

異常的特性:

一個(gè)try可以有多個(gè)catch塊,但運(yùn)行時(shí)只有一個(gè)catch塊可以被執(zhí)行,并且是按照順序來尋找匹配的catch塊的,所以需要將父類的異常需要放在后面的catch塊中

try{
test.method(str);
}catch (MyException e)
{
System.out.println("MyException catch");
e.printStackTrace();
}catch(MyException2 e)
{
System.out.println("MyException2 catch");
e.printStackTrace();
}catch(Exception e)
{
System.out.println(“Exception catch”);
e.printStackTrace();
}
finally
{System.out.println("finally");
}

try{
test.method(str);
}catch(Exception e)
{
System.out.println(“Exception catch”);
e.printStackTrace();
}
catch (MyException e)
{
System.out.println("MyException catch");
e.printStackTrace();
}catch(MyException2 e)
{
System.out.println("MyException2 catch");
e.printStackTrace();
}
finally
{System.out.println("finally");
}

面試題目

題目一:

package defineexception;
public class ExceptionTest3
{
    public void method()
    {
        try
        {
            System.out.println("try");
            return;
        }
        catch(Exception ex)
        {
            System.out.println("異常發(fā)生了");
        }
        finally
        {
            System.out.println("finally");
        }
        System.out.println("異常處理后續(xù)的代碼");
    }
    public static void main(String[] args)
    {
        ExceptionTest3 test =new ExceptionTest3();
        test.method();
    }
}

結(jié)果:

try
finally

分析

try塊中存在return語句,那么首先也需要將finally塊中的代碼執(zhí)行完畢,再執(zhí)行return語句,而且之后的其他代碼也不會(huì)再執(zhí)行了

題目二:

package defineexception;
public class ExceptionTest3
{
    public void method()
    {
        try
        {
            System.out.println("try");
            System.exit(0);
        }
        catch(Exception ex)
        {
            System.out.println("異常發(fā)生了");
        }
        finally
        {
            System.out.println("finally");
        }
        System.out.println("異常處理后續(xù)的代碼");
    }
    public static void main(String[] args)
    {
        ExceptionTest3 test =new ExceptionTest3();
        test.method();
    }
}

結(jié)果

try

分析

先執(zhí)行try塊中的System.exit(0)語句,已經(jīng)退出了虛擬機(jī)系統(tǒng),所以不會(huì)執(zhí)行finally塊的代碼

參考鏈接

https://www.jb51.net/article/161574.htm

更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java面向?qū)ο蟪绦蛟O(shè)計(jì)入門與進(jìn)階教程》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》

希望本文所述對大家java程序設(shè)計(jì)有所幫助。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI