Java 基礎(chǔ):異常

目錄:
一、 異常繼承體系
二、 發(fā)生異常到時候般堆,程序的執(zhí)行特征:
三在孝、 異常與錯誤的區(qū)別
四、 拋出異常 throw
五淮摔、 聲明異常 throws
六私沮、 捕獲異常 try…catch…finally
七、 try…catch…finally 異常處理的組合方式
八和橙、 異常在方法重寫中細(xì)節(jié)
九仔燕、 Throwable 類中的常用方法
十、 try和finally中都有return語句魔招,執(zhí)行哪一個 return晰搀?
十一、 自定義異常


一办斑、 異常繼承體系

  • 異常是程序運行過程中出現(xiàn)的錯誤外恕。Java 把異常當(dāng)作對象來處理,把異常信息封裝成了一個乡翅,并定義一個基類 java.lang.Throwable 作為所有異常的超類鳞疲。
  • Throwable : 它是所有錯誤與異常的超類(祖宗類),有兩個子類ErrorException
    • Error : 錯誤。程序無法處理的錯誤蠕蚜,比如OutOfMemoryError建丧、ThreadDeath等。這些異常發(fā)生時波势,Java虛擬機(JVM)一般會選擇線程終止翎朱。
    • Exception : 異常。程序本身可以處理的異常尺铣,程序中應(yīng)當(dāng)盡可能去處理這些異常拴曲。
      • RuntimeException : 運行期異常, JAVA程序運行過程中出現(xiàn)的問題
      • CheckableException : 編譯時異常或者可檢查異常, 是除了RuntimeExecption(及其子類)之外的所有 Exception
  • 運行時期異常:
    • 方法中拋出運行時期異常,方法定義中無需throws聲明,調(diào)用者也無需處理此異常
    • 運行時期異常一旦發(fā)生,需要程序人員修改源代碼.
  • 編譯時異常: 必須在編譯前處理,否則無法通過編譯

二凛忿、 發(fā)生異常到時候澈灼,程序的執(zhí)行特征:

  • 我們的代碼,從發(fā)生異常的地方店溢,開始被一分為二
  • 在異常發(fā)生之前的代碼叁熔,都可以正常運行,之后的代碼不會執(zhí)行
  • 當(dāng)異常發(fā)生的時候床牧,這個異常被 jvm 所捕獲荣回,并將這個異常的所有相關(guān)信息,創(chuàng)建為一個異常對象戈咳,然后將該異常對象的信息輸出到控制臺(執(zhí)行的是虛擬機默認(rèn)的異常處理代碼)
  • 終止當(dāng)前程序

三心软、 異常與錯誤的區(qū)別

  • 異常:指程序在編譯壕吹、運行期間發(fā)生了某種異常(XxxException),我們可以對異常進(jìn)行具體的處理删铃。若不處理異常耳贬,程序?qū)Y(jié)束運行。
  • 錯誤:指程序在運行期間發(fā)生了某種錯誤(XxxError)猎唁,Error 錯誤通常沒有具體的處理方式咒劲,程序?qū)Y(jié)束運行。Error錯誤的發(fā)生往往都是系統(tǒng)級別的問題诫隅,都是jvm所在系統(tǒng)發(fā)生并反饋給jvm的腐魂。我們無法針對處理,只能修正代碼阎肝。

四、 拋出異常 throw

  • 在 java 中肮街,提供了一個throw關(guān)鍵字风题,它用來拋出一個指定的(Throwable類型)異常對象.
  • 一般會用于程序出現(xiàn)某種邏輯時,程序員主動拋出某種特定類型的異常
  • 具體步驟:
    • 創(chuàng)建一個異常對象, 封裝一些提示信息(信息可以自己編寫).
    • 通過關(guān)鍵字 throw, 將這個異常對象告知給調(diào)用者.
    • throw 用在方法內(nèi)嫉父,用來拋出一個異常對象沛硅,將這個異常對象傳遞到調(diào)用者處,并結(jié)束當(dāng)前方法的執(zhí)行绕辖。
  • 使用格式throw new 異常類名(參數(shù));
throw new NullPointerException("要訪問的arr數(shù)組不存在");
throw new ArrayIndexOutOfBoundsException("該索引在數(shù)組中不存在摇肌,已超出范圍");
//具體范例:
public static void main(String[] args) {
    String s = "abc";
    if(s.equals("abc")) {
        throw new NumberFormatException();
    } else {
        System.out.println(s);
    }
    //function();
}
  • 注意事項
    • 如果拋出的異常對象屬于可檢查的異常,必須在該方法頭部仪际,聲明拋出此異常, 即: throws 要拋出的異常類型
    • 其次围小,對于拋出可檢查的異常,還必須與方法的異常列表中的異常兼容
    • 如果父類方法聲明了異常列表
      • 子類可以不聲明異常列表
      • 子類方法有自己異常列表時树碱,必須保證肯适,子類的異常列表所包含的異常類型,與父類中所包含的異常類型兼容

五成榜、 聲明異常 throws

  • 聲明:將問題標(biāo)識出來框舔,報告給調(diào)用者
  • throws 是方法可能拋出異常的聲明, 如果定義功能時有問題發(fā)生需要報告給調(diào)用者∈昊椋可以通過在方法上使用 throws 關(guān)鍵字進(jìn)行聲明刘绣。
  • 對于聲明了會拋出可檢查異常的方法, 就意味著這個方法會產(chǎn)生可檢查異常,所以挣输,一旦調(diào)用該方法就必須對該方法做異常處理
  • throws 用于進(jìn)行異常類的聲明纬凤,若該方法可能有多種異常情況產(chǎn)生,那么在 throws 后面可以寫多個異常類撩嚼,用逗號隔開移斩。
  • 聲明異常格式修飾符 返回值類型 方法名(參數(shù)) throws <異常列表> { }
public static void function() throws NumberFormatException{
        String s = "abc";
        System.out.println(Double.parseDouble(s));
    }

    public static void main(String[] args) {
        try {
            function();
        } catch (NumberFormatException e) {
            System.err.println("非數(shù)據(jù)類型不能轉(zhuǎn)換肚医。");
        }
}

六、 捕獲異常 try…catch…finally

1. 概述
  • 捕獲:Java中對異常有針對性的語句進(jìn)行捕獲向瓷,可以對出現(xiàn)的異常進(jìn)行指定方式的處理
  • 捕獲異常格式
try {
    //需要被檢測的語句肠套。
}
catch(異常類 e) { //try中拋出的是什么異常,在括號中就定義什么異常類型猖任。
    //異常的處理語句你稚。
}
finally {
    //一定會被執(zhí)行的語句。
}
//try:該代碼塊中編寫可能產(chǎn)生異常的代碼朱躺。
//catch:用來進(jìn)行某種異常的捕獲刁赖,實現(xiàn)對捕獲到的異常進(jìn)行處理。
//finally:有一些特定的代碼無論異常是否發(fā)生长搀,都需要執(zhí)行宇弛。另外,因為異常會引發(fā)程序跳轉(zhuǎn)源请,導(dǎo)致有些語句執(zhí)行不到枪芒。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執(zhí)行的谁尸。
  • 某個函數(shù)或某段程序塊不管會不會舅踪,有沒可能拋出異常,都可以加try{...}catch{...}去捕捉它良蛮。
2. 異常處理流程:
  1. 首先抽碌,當(dāng)異常在 try 代碼塊中發(fā)生的時候,虛擬機首先捕獲這個異常决瞳,創(chuàng)建一個異常對象(包含本次異常的所有詳細(xì)信息)
  2. 虛擬機會把這個異常货徙,拋出給catch代碼塊(類似于方法調(diào)用,虛擬機會調(diào)用catch代碼塊中皮胡,處理異常的代碼)
  3. 執(zhí)行catch代碼塊破婆,中的處理異常的代碼
  4. 沒有終止我們應(yīng)用程序,而是從catch語句之后的代碼開始胸囱,繼續(xù)執(zhí)行我們的應(yīng)用程序

在try語句塊中祷舀,一旦發(fā)生異常,我們的代碼仍然被一分為二

  1. 在異常發(fā)生之前帶代碼都正常運行
  2. 在異常發(fā)生之后的代碼烹笔,不會執(zhí)行裳扯,而是直接跳轉(zhuǎn)到我們自己處理異常的catch代碼塊中

七、 try…catch…finally 異常處理的組合方式

  • try catch finally組合: 檢測異常谤职,并傳遞給 catch 處理饰豺,并在 finally 中進(jìn)行資源釋放。

即使在finally代碼塊執(zhí)行了return語句允蜈,finally代碼塊中的代碼冤吨,仍然會執(zhí)行
特殊情況: 走到finally之前 JVM 退出了,就不會執(zhí)行finally了
finally在開發(fā)中的應(yīng)用:用于釋放資源

  • try catch組合 : 對代碼進(jìn)行異常檢測蒿柳,并對檢測的異常傳遞給catch處理。對異常進(jìn)行捕獲處理
  • 多個try catch組合 當(dāng)可能有多種類型的異常發(fā)生的時候漩蟆,我把可能產(chǎn)生某異常類型的代碼分開垒探,分別放在不同的try-catch代碼塊中
  • 執(zhí)行特征是:
    • 每個try-catch中是否拋出異常,相互獨立的
    • 在實際執(zhí)行的時候怠李,每一個try-catch代碼塊可能都產(chǎn)生異常圾叼。
  • 實際開發(fā)的時候,一般來講:
    • 效率角度捺癞,try 塊中方的代碼越少越好
    • 開發(fā)的時候夷蚊,會將相關(guān)的異常,放在同一個 try 塊
      • 相關(guān)異常: 一個連續(xù)的流程中髓介,可能發(fā)生的一系列異常
      • 所以一系列相關(guān)的流程中惕鼓,一旦前一步出現(xiàn)了異常,就會導(dǎo)致唐础,即使后面的流程正常執(zhí)行箱歧,其實也已經(jīng)沒有意義了
  • 一個try 多個catch組合 : 對代碼進(jìn)行異常檢測,并對檢測的異常傳遞給catch處理彻犁。對每種異常信息進(jìn)行不同的捕獲處理叫胁。

這種異常處理方式凰慈,要求多個catch中的異常不能相同汞幢,
catch中的多個異常之間有子父類異常的關(guān)系,那么先寫子類異常類型微谓,再寫父類異常類型
當(dāng)發(fā)生異常的時候森篷, 最多執(zhí)行一個catch分支的代碼

public class Demo {
    public static void main(String[] args) {
        try{
            int i = 10;
            //可能發(fā)生異常的語句
            int j = i / 0;
            System.out.println("try after exception");
            //空指針異常
            int[] a = null;
            System.out.println(a[0]);
            //數(shù)組越界異常
            int[] b = {1, 2, 3};
            System.out.println(b[3]);
        }catch (ArithmeticException e) {
            System.out.println("發(fā)生了除0異常");
        } catch (NullPointerException | ArrayIndexOutOfBoundsException e) { //一個catch分支處理多種類型的異常
            System.out.println("發(fā)生了數(shù)組異常");
        }
    }
}
  • try finally 組合: 對代碼進(jìn)行異常檢測,檢測到異常后因為沒有catch豺型,所以一樣會被默認(rèn) jvm 拋出仲智。異常是沒有捕獲處理的。但是功能所開啟資源需要進(jìn)行關(guān)閉姻氨,所以 finally 只為關(guān)閉資源

八钓辆、 異常在方法重寫中細(xì)節(jié)

  • 子類覆蓋父類方法時,如果父類的方法聲明異常肴焊,子類只能聲明父類異常或者該異常的子類前联,或者不聲明
class Fu {
    public void method () throws RuntimeException {
    }
}

class Zi extends Fu {
    public void method() throws RuntimeException { }  //拋出父類一樣的異常
    //public void method() throws NullPointerException{ } //拋出父類子異常
}
  • 當(dāng)父類方法聲明多個異常時娶眷,子類覆蓋時只能聲明多個異常的子集似嗤。
class Fu {
    public void method () throws NullPointerException, ClassCastException{
    }
}
class Zi extends Fu {
    public void method()throws NullPointerException, ClassCastException { }
    public void method() throws NullPointerException{ } //拋出父類異常中的一部分
    public void method() throws ClassCastException { } //拋出父類異常中的一部分
}
  • 當(dāng)被覆蓋的方法沒有異常聲明時,子類覆蓋時無法聲明異常的届宠。

九烁落、 Throwable類中的常用方法

  • getCause():返回拋出異常的原因乘粒,即異常提示信息。如果 cause 不存在或未知伤塌,則返回 null灯萍。
  • getMessage():返回異常的消息信息,即該異常的名稱與詳細(xì)信息字符串
  • printStackTrace():在控制臺輸出該異常的名稱與詳細(xì)信息字符串寸谜、異常出現(xiàn)的代碼位置

十竟稳、 try和finally中都有return語句,執(zhí)行哪一個return熊痴?

  • 首先要確定的一點是他爸,不管有木有出現(xiàn)異常,finally塊中代碼都會執(zhí)行
  • 當(dāng)try和catch中有return時果善,finally仍然會執(zhí)行诊笤;
  • finally是在return后面的表達(dá)式運算后執(zhí)行的(此時并沒有返回運算后的值,而是先把要返回的值保存起來巾陕,不管finally中的代碼怎么樣讨跟,返回的值都不會改變,任然是之前保存的值)鄙煤,所以函數(shù)返回值是在finally執(zhí)行前確定的晾匠;
  • finally中最好不要包含return,否則程序會提前退出梯刚,返回值不是try或catch中保存的返回值凉馆。

問:如果try和finally語句里面都有return,會執(zhí)行哪一個呢亡资?
首先澜共,在程序沒有異常的情況下,首先執(zhí)行到try里面的語句锥腻,但是只執(zhí)行到了return里面的****expression嗦董,expression首先存放在操作數(shù)棧頂,然后復(fù)制到局部變量區(qū)瘦黑,并沒有執(zhí)行返回語句return(執(zhí)行返回語句通常意味著程序執(zhí)行結(jié)束)京革。然后執(zhí)行finally,當(dāng)執(zhí)行到finally里面的return時候幸斥,會將return語句執(zhí)行完整匹摇,此時程序已經(jīng)有了返回值,因為睡毒,執(zhí)行結(jié)束来惧。

  • 總結(jié):執(zhí)行try塊,執(zhí)行到return語句時演顾,先執(zhí)行return的語句供搀,但是不返回到main 方法隅居,接下來執(zhí)行finally塊,遇到finally塊中的return語句葛虐,執(zhí)行,并將值返回到main方法胎源,這里就不會再回去返回try塊中計算得到的值

十一、 自定義異常

1. 概述
  • 如果Java沒有提供你需要的異常屿脐,則可以自定義異常類涕蚤。
  • 編譯時異常繼承 Exception,運行時異常繼承 RuntimeException
  • 格式:
Class 異常名 extends Exception{ //或繼承RuntimeException
    public 異常名(){
    }
    public 異常名(String s){
        super(s);
    }
}
2. 示例

需求描述:
定義Person類的诵,包含name與age兩個成員變量万栅。
在Person類的有參數(shù)構(gòu)造方法中,進(jìn)行年齡范圍的判斷西疤,若年齡為負(fù)數(shù)或大于200歲烦粒,則拋出NoAgeException異常,異常提示信息“年齡數(shù)值非法”代赁。
要求:在測試類中扰她,調(diào)用有參數(shù)構(gòu)造方法,完成Person對象創(chuàng)建芭碍,并進(jìn)行異常的處理徒役。

//自定義異常類
class NoAgeException extends Exception{
    NoAgeException() {
        super();
    }

    NoAgeException(String message)  {
        super(message);
    }
}

//Person類
class Person{
    private String name;
    private int age;
    Person(String name,int age) throws NoAgeException   {
        //加入邏輯判斷
        if(age<0 || age>200)        {
            throw new NoAgeException(age+",年齡數(shù)值非法");
        }
        this.name = name;
        this.age = age;
    }
    //定義Person對象對應(yīng)的字符串表現(xiàn)形式。覆蓋Object中的toString方法窖壕。
    public String toString()    {
        return "Person[name="+name+",age="+age+"]";
    }
}

//測試類
class ExceptionDemo{
    public static void main(String[] args) {
        try {
            Person p = new Person("xiaoming",20);
            System.out.println(p);
        }
        catch (NoAgeException ex){
            System.out.println("年齡異常啦");
        }
        System.out.println("over");
    }
}

總結(jié)一下忧勿,構(gòu)造函數(shù)到底拋出這個NoAgeException是繼承Exception呢?還是繼承RuntimeException呢艇拍?
繼承Exception狐蜕,必須要throws聲明宠纯,一聲明就告知調(diào)用者進(jìn)行捕獲卸夕,一旦問題處理了調(diào)用者的程序會繼續(xù)執(zhí)行。
繼承RuntimeExcpetion,不需要throws聲明的婆瓜,這時調(diào)用是不需要編寫捕獲代碼的快集,因為調(diào)用根本就不知道有問題。一旦發(fā)生NoAgeException廉白,調(diào)用者程序會停掉个初,并有jvm將信息顯示到屏幕,讓調(diào)用者看到問題猴蹂,修正代碼院溺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市磅轻,隨后出現(xiàn)的幾起案子珍逸,更是在濱河造成了極大的恐慌逐虚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谆膳,死亡現(xiàn)場離奇詭異叭爱,居然都是意外死亡,警方通過查閱死者的電腦和手機漱病,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門买雾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杨帽,你說我怎么就攤上這事漓穿。” “怎么了注盈?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵器净,是天一觀的道長。 經(jīng)常有香客問我当凡,道長山害,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任沿量,我火速辦了婚禮浪慌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朴则。我一直安慰自己权纤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布乌妒。 她就那樣靜靜地躺著汹想,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撤蚊。 梳的紋絲不亂的頭發(fā)上古掏,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音侦啸,去河邊找鬼槽唾。 笑死,一個胖子當(dāng)著我的面吹牛光涂,可吹牛的內(nèi)容都是我干的庞萍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼忘闻,長吁一口氣:“原來是場噩夢啊……” “哼钝计!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤私恬,失蹤者是張志新(化名)和其女友劉穎交播,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體践付,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡秦士,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了永高。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隧土。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖命爬,靈堂內(nèi)的尸體忽然破棺而出曹傀,到底是詐尸還是另有隱情,我是刑警寧澤饲宛,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布皆愉,位于F島的核電站,受9級特大地震影響艇抠,放射性物質(zhì)發(fā)生泄漏幕庐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一家淤、第九天 我趴在偏房一處隱蔽的房頂上張望异剥。 院中可真熱鬧,春花似錦絮重、人聲如沸冤寿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽督怜。三九已至,卻和暖如春狠角,著一層夾襖步出監(jiān)牢的瞬間号杠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工擎厢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留究流,地道東北人辣吃。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓动遭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親神得。 傳聞我的和親對象是個殘疾皇子厘惦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容