Java--異常詳解

異常分類

如果某個(gè)方法不能按照正常的途徑完成任務(wù),就可以通過另一種路徑退出方法表悬。在這種情況下會(huì)拋出一個(gè)封裝了錯(cuò)誤信息的對(duì)象弥锄。此時(shí),這個(gè)方法會(huì)立刻退出同時(shí)不返回任何值蟆沫。另外,調(diào)用這個(gè)方法的其他代碼也無法繼續(xù)執(zhí)行温治,異常處理機(jī)制會(huì)將代碼執(zhí)行交給異常處理器饭庞。

image-20200811183913204

Throwable

Throwable 是 Java 語言中所有錯(cuò)誤或異常的超類。

也就是說熬荆,如果你要拋出或者聲明一個(gè)異常舟山,那么,這個(gè)異常必須繼承Throwable.

public class Main {

    public static void main(String[] args) {

    }


    public void testMyError() throws MyError{
        throw new MyError();
    }

    public void testMyErrorNon() throws MyErrorNon {
        throw new MyErrorNon();
    }

    public void testMyException() throws MyException {
        throw new MyException();
    }

    public void testMyExceptionNon() throws MyExceptionNon{
        throw new MyExceptionNon();
    }
}
image-20200811185444881

Error

Error 類是指 java 運(yùn)行時(shí)系統(tǒng)的內(nèi)部錯(cuò)誤和資源耗盡錯(cuò)誤。應(yīng)用程序不會(huì)拋出該類對(duì)象累盗。如果出現(xiàn)了這樣的錯(cuò)誤寒矿,除了告知用戶,剩下的就是盡力使程序安全的終止.

image-20200811185821287

Exception

image-20200811185851801

Exception 又 有 兩 個(gè) 分 支 若债, 一 個(gè) 是 運(yùn) 行 時(shí) 異 常 RuntimeException 符相, 一個(gè)是CheckedException.

RuntimeExceptionn

運(yùn)行時(shí)異常

如 : NullPointerException 、 ClassCastException 蠢琳; 一 個(gè) 是 檢 查 異 常CheckedException啊终,如 I/O 錯(cuò)誤導(dǎo)致的 IOException、SQLException傲须。 RuntimeException 是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類蓝牲。 如果出現(xiàn) RuntimeException,那么一定是程序員的錯(cuò)誤.

CheckedException

檢查異常

一般是外部錯(cuò)誤泰讽,這種異常都發(fā)生在編譯階段例衍,Java 編譯器會(huì)強(qiáng)制程序去捕獲此類異常,即會(huì)出現(xiàn)要求你把這段可能出現(xiàn)異常的程序進(jìn)行 try catch已卸,該類異常一
般包括幾個(gè)方面:

  1. 試圖在文件尾部讀取數(shù)據(jù)
  2. 試圖打開一個(gè)錯(cuò)誤格式的 URL
  3. 試圖根據(jù)給定的字符串查找 class 對(duì)象肄渗,而這個(gè)字符串表示的類并不存在

異常處理方式

throw

image-20200811190156250

throws

image

jvm自動(dòng)拋出

image-20200811190226930
image-20200811190236707

throw和throws的異同

相同點(diǎn):

  1. 都繼承Throwable
  2. 程序的執(zhí)行順序收到影響
  3. 不一定每次都出現(xiàn),概率不確定
  4. 消極處理異常的方式咬最,只是拋出或者可能拋出異常翎嫡,但是不會(huì)由方法去處理異常,真正的處理異常常有方法的調(diào)用者處理永乌。

不同點(diǎn):

  • 位置不同:
    1. ==throws用在方法上== 惑申,后面跟的是異常類,可以跟多個(gè)翅雏;==而throw用在方法內(nèi)==圈驼,后面跟的是異常對(duì)象。
  • 功能不同:
    1. throws用來聲明異常望几,==讓調(diào)用者知道該方法可能出現(xiàn)的問題==绩脆,可以給出預(yù)先的處理方式;==throw拋出具體的異常問題對(duì)象==橄抹,執(zhí)行到throw靴迫,就無法在繼續(xù)按正常的順序繼續(xù)執(zhí)行了。跳轉(zhuǎn)到調(diào)用者楼誓,并將具體的問題對(duì)象拋給調(diào)用者玉锌。
    2. throws表示==出現(xiàn)異常的一種可能性==,并不一定會(huì)發(fā)生這些異常疟羹;throw則是==拋出了異常==主守,執(zhí)行throw則一定拋出了某種異常禀倔。

異常的捕獲

image-20200811192641646
public class Main {

    public static void main(String[] args) {
        try {
            testcatch();
        } catch (MyException4 myException4) {
            myException4.printStackTrace();
        } catch (MyException3 myException3) {
            myException3.printStackTrace();
        } catch (MyException2 myException2) {
            myException2.printStackTrace();
        } catch (MyException1 myException1) {
            myException1.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    public static void testcatch() throws Throwable, MyException4, MyException3, MyException2, MyException1, Exception, Error {
    }

}

異常的捕獲,最靠近try的参淫,異常范圍是最小的救湖。異常匹配時(shí),從上到下進(jìn)行匹配涎才,如果將范圍大的異常捕獲放在前面鞋既,那么后面比這個(gè)異常范圍小的異常,永遠(yuǎn)得不到調(diào)用憔维。

異常調(diào)用鏈

每個(gè)方法內(nèi)部出現(xiàn)異常后涛救,要么方法內(nèi)部使用try捕獲異常,方法內(nèi)解決這個(gè)異常业扒。使程序繼續(xù)運(yùn)行下去检吆。

要么將異常拋出,由方法的調(diào)用者處理這個(gè)異常程储。

public class OMain {

    public static void main(String[] args) {
        try {
            new OMain().test4();
        } catch (MyException4 myException4) {
            myException4.printStackTrace();
        }
    }

    public void test4() throws MyException4 {
        try {
            test3();
        } catch (MyException3 myException3) {
            throw new MyException4();
        }
    }

    public void test3() throws MyException3 {
        try {
            test2();
        } catch (MyException2 myException2) {
            throw new MyException3();
        }
    }

    public void test2() throws MyException2 {
        try {
            test1();
        } catch (MyException1 myException1) {
            throw new MyException2();
        }
    }

    public void test1() throws MyException1 {
        try {
            test();
        } catch (Exception e) {
            throw new MyException1();
        }
    }

    public void test() throws Exception {
        throw new Exception();
    }

}

在這個(gè)例子中蹭沛,真正的異常是在test方法中出現(xiàn)的,但是因?yàn)槊恳粋€(gè)方法都在自己的方法內(nèi)部捕獲了下層異常章鲤,然后拋出自己的異常摊灭。

此時(shí)整個(gè)異常已經(jīng)失真了,從異常堆棧根本無法知道問題出在哪里:

image-20200811193704999

異常調(diào)用鏈的完整败徊,可以幫助我們更快的定位問題帚呼。

public class OMain {

    public static void main(String[] args) {
        try {
            new OMain().test4();
        } catch (MyException4 myException4) {
            myException4.printStackTrace();
        }
    }

    public void test4() throws MyException4 {
        try {
            test3();
        } catch (MyException3 myException3) {
            MyException4 myException4 = new MyException4();
            myException4.initCause(myException3);
            throw myException4;
        }
    }

    public void test3() throws MyException3 {
        try {
            test2();
        } catch (MyException2 myException2) {
            MyException3 myException3 = new MyException3();
            myException3.initCause(myException2);
            throw myException3;
        }
    }

    public void test2() throws MyException2 {
        try {
            test1();
        } catch (MyException1 myException1) {
            MyException2 myException2 = new MyException2();
            myException2.initCause(myException1);
            throw myException2;
        }
    }

    public void test1() throws MyException1 {
        try {
            test();
        } catch (Exception e) {
            MyException1 myException1 = new MyException1();
            myException1.initCause(e);
            throw myException1;
        }
    }

    public void test() throws Exception {
        throw new Exception();
    }

}

在Throwable中,有一個(gè)屬性cause,默認(rèn)是自己皱蹦。這個(gè)屬性就是記錄當(dāng)前異常的上一個(gè)異常是誰煤杀。如果cause就是自己,那么沪哺,說明這個(gè)異常就是最先拋出的異常沈自。

image-20200811194520023

這樣整個(gè)異常調(diào)用鏈就完整了:

image-20200811194652221

其調(diào)用關(guān)系,可以完整的從堆棧中看出辜妓。

這是最常見的場(chǎng)景枯途。

我們假設(shè)這個(gè)調(diào)用是上下級(jí)的調(diào)用:

test4->test3->test2->test1->test

其中越是下級(jí),做的工作越簡(jiǎn)單籍滴,也越是底層方法的調(diào)用酪夷。在底層方法得到調(diào)用中,就會(huì)出現(xiàn)各種各樣的異常(什么異常都有可能)

在例子中出現(xiàn)的是Exception异逐。

在test方法中捶索,可能完全不明白為什么出現(xiàn)異常,或者說灰瞻,出現(xiàn)異常的原因是什么腥例,如何解決?這些問題在test方法中都無法解決的酝润。

于是test方法將自己無法解決的異常拋出燎竖。

在test1方法中,捕獲到了異常要销,可能test1交給test是讀取一個(gè)文件构回,結(jié)果出現(xiàn)了文件沒找到的異常。那么疏咐,在test1方法中就知道了纤掸,是文件沒找到,但是浑塞,對(duì)于沒找到的文件借跪,該如何處理呢?test1就不知道了酌壕,于是掏愁,繼續(xù)向上拋出異常,此時(shí)異常被進(jìn)行細(xì)化卵牍,由文件沒找到的異常轉(zhuǎn)換為文件讀取失敗果港。

在test2方法中,捕獲到了異常糊昙,可能test2交給test1是讀取一個(gè)文件夾的文件辛掠,結(jié)果出現(xiàn)了部分文件未找到。那么在test2方法中释牺,我們知道了萝衩,是部分文件沒找到,而不是文件夾內(nèi)全部的文件沒找到船侧。在test2方法中欠气,可以確定,是某一個(gè)文件沒有找到镜撩,那么對(duì)于這個(gè)文件预柒,我們是要忽略,還是重試呢袁梗?test2也不知道宜鸯,此時(shí)只能轉(zhuǎn)換異常,然后繼續(xù)拋出遮怜。轉(zhuǎn)換的異常更加細(xì)化淋袖,部分文件未找到。

锯梁。即碗。焰情。。

以此類推剥懒,最終異常被交給了主線程内舟,當(dāng)主線程也無法確認(rèn)后,將問題拋給用戶初橘,由用戶決定验游。用戶決定如何處理。

這個(gè)過程可以類比我們使用操作系統(tǒng)復(fù)制整個(gè)文件夾的過程保檐。

里面是一層層的劃分耕蝉,當(dāng)出現(xiàn)無法抉擇的異常,最終拋給用戶決定夜只。

遇到可以抉擇的異常垒在,直接處理。(一個(gè)文件失敗自動(dòng)重試3次盐肃。爪膊。)

將異常交由調(diào)用者處理,是非常正確的處理方式砸王。\

==這種方式是金字塔結(jié)構(gòu)推盛,越是底層的方法,異常范圍越大谦铃。==

==還有一種是倒金字塔結(jié)構(gòu)耘成,越是底層的方法,異常越小驹闰。==對(duì)于這種結(jié)構(gòu)瘪菌,無需做任何捕獲,直接拋出即可嘹朗。

public class OMain {

    public static void main(String[] args) {
        try {
            new OMain().test();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public void test4() throws MyException4 {
        throw new MyException4();
    }

    public void test3() throws MyException3 {
        test4();
    }

    public void test2() throws MyException2 {
            test3();
    }

    public void test1() throws MyException1 {
            test2();
    }

    public void test() throws Throwable {
            test1();
    }

}
image-20200811200302026
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末师妙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屹培,更是在濱河造成了極大的恐慌默穴,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件褪秀,死亡現(xiàn)場(chǎng)離奇詭異蓄诽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)媒吗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門仑氛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事锯岖〗橥啵” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵嚎莉,是天一觀的道長米酬。 經(jīng)常有香客問我沛豌,道長趋箩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任加派,我火速辦了婚禮叫确,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芍锦。我一直安慰自己竹勉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布娄琉。 她就那樣靜靜地躺著次乓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪孽水。 梳的紋絲不亂的頭發(fā)上票腰,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音女气,去河邊找鬼杏慰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛炼鞠,可吹牛的內(nèi)容都是我干的缘滥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼谒主,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼朝扼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起霎肯,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤擎颖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后姿现,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肠仪,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年备典,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了异旧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡提佣,死狀恐怖吮蛹,靈堂內(nèi)的尸體忽然破棺而出荤崇,到底是詐尸還是另有隱情,我是刑警寧澤潮针,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布术荤,位于F島的核電站,受9級(jí)特大地震影響每篷,放射性物質(zhì)發(fā)生泄漏瓣戚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一焦读、第九天 我趴在偏房一處隱蔽的房頂上張望子库。 院中可真熱鬧,春花似錦矗晃、人聲如沸仑嗅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仓技。三九已至,卻和暖如春俗他,著一層夾襖步出監(jiān)牢的瞬間脖捻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工拯辙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留郭变,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓涯保,卻偏偏與公主長得像诉濒,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夕春,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345