Java中的異常處理

如果我們制作一個計(jì)算器程序,當(dāng)用戶輸入的除數(shù)為0時,程序?qū)罎⒅苯油顺瞿己荆敲丛摮绦虻挠脩趔w驗(yàn)將會非常差。我們應(yīng)該告訴用戶语盈,除數(shù)為0是不被允許的并繼續(xù)讓用戶使用該程序舱馅,而不是異常退出!這就要用到異常處理程序了刀荒。

簡單介紹

異常是指阻止當(dāng)前方法或作用域繼續(xù)執(zhí)行的問題代嗤。而異常處理的任務(wù)就是將程序從錯誤狀態(tài)中恢復(fù)棘钞,來讓程序要么換一種方式運(yùn)行,要么繼續(xù)運(yùn)行下去干毅!因此宜猜,我們在寫程序時需要考慮到程序?qū)霈F(xiàn)哪些異常,并將其捕獲處理硝逢,保證用戶不會接觸到它姨拥。

異常的繼承體系

如下圖,我們可以看到所有異常都是由Throwable繼承而來趴捅。其后面還有兩個分支:Error,Exception 垫毙。

當(dāng)出現(xiàn)Error問題時,一般都是系統(tǒng)內(nèi)部錯誤或者資源耗盡等才會發(fā)生拱绑,我們一般不關(guān)注此類問題(當(dāng)然也無能為力)。我們主要考慮程序本身將會出現(xiàn)的問題(Exception)丽蝎。我們一般主要將Exception分為RuntimeExceptioncheck Exception猎拨。

出現(xiàn)RuntimeException時,表明程序本身存在錯誤屠阻,編譯時會通過红省,但運(yùn)行時會出現(xiàn)錯誤。此類異彻酰可以不捕捉處理或拋出吧恃,運(yùn)行時由JVM拋出給調(diào)用者或者虛擬機(jī)。

出現(xiàn)check Exception我們必須捕捉處理或者向上拋出給調(diào)用者麻诀,否則無法通過編譯處理痕寓。

語法說明

我們通常所說的異常捕獲,一般使用try函數(shù)來完成蝇闭,異常處理一般使用 catch函數(shù)完成呻率,處理完成一般還會使用finally來處理其他一定要做的事情(比如數(shù)據(jù)庫的連接中斷、文件的讀取關(guān)閉)呻引。

try catch

捕獲異常

try{
  //可能會出錯的程序
}

處理異常

//捕獲多個異常時礼仗,父類異常應(yīng)該在子類異常下面出現(xiàn)
try{
  //可能會出錯的程序
} catch(Exception1 e){
  //出現(xiàn)問題Exception1的處理方法
} catch(Exception2|Exception3 e){
  //出現(xiàn)問題Exception2或者Exception3的處理方法
}
...
 finally{
   //處理完問題一定會執(zhí)行的代碼
 }

拋出異常throws

//我們一直拋出異常直到傳遞給調(diào)用者
void func() throws Exception1,Exception2{
  
}

public static void main(String[] args) throws Exception1,Exception2{
  func();
}

處理方式比較

異常處理過程

拋出異常時,首先逻悠,同Java中其他對象一樣元践,將使用new在堆上創(chuàng)建異常對象。然后童谒,當(dāng)前路徑的執(zhí)行被終止单旁,并且從當(dāng)前環(huán)境中彈出對異常對象的引用。此時惠啄,異常處理機(jī)制開始接管程序并且使用異常處理程序繼續(xù)執(zhí)行程序慎恒!異常處理程序的任務(wù)是將程序從錯誤中恢復(fù)并換一種方式運(yùn)行或者繼續(xù)執(zhí)行下去任内!

異常處理的兩種模型

終止模型:一旦異常被拋出,就表明異常已經(jīng)無法挽回融柬,也不能回來繼續(xù)執(zhí)行死嗦!

恢復(fù)模型:希望能夠處理異常并繼續(xù)執(zhí)行程序,此時粒氧,異常不能拋出只能調(diào)用方法修正該錯誤越除,或者,把try塊放到while循環(huán)里外盯,不斷進(jìn)入try摘盆,直到得到滿意結(jié)果為止!

對于兩種模型饱苟,程序員大多最終轉(zhuǎn)向了終止模型的代碼孩擂,并且忽略恢復(fù)行為。因?yàn)榛謴?fù)模型可能導(dǎo)致的耦合性:恢復(fù)性的處理程序需要了解異常拋出的地點(diǎn)箱熬,這勢必要包含依賴于拋出位置的非通用性代碼类垦,這增加了代碼的編寫與維護(hù)的困難。因此我們應(yīng)該盡量解決能解決的問題城须,其他的都拋給調(diào)用者蚤认!

自定義異常

簡單介紹

我們已經(jīng)知道異常都是基于Throwable的,但我們一般只關(guān)注Exception糕伐。因此我們自定義的異常類一般都是Exception的子類砰琢。

  • 異常有兩個構(gòu)造器,有參構(gòu)造器的參數(shù)是出現(xiàn)異常時你想要顯示的信息良瞧。
  • 方法內(nèi)部我們使用throw拋出異常陪汽,方法要想向上拋出異常需要使用throws
  • try塊中,如果異常已經(jīng)觸發(fā)莺褒,try中異常觸發(fā)后下面的代碼不執(zhí)行
  • 我們可以使用e.getMessage()掩缓,e.toString()e.printStackTrace();顯示錯誤信息,前兩者需要借助print輸出遵岩,且三者輸出的信息量呈遞增你辣。
  • e.getMessage()只輸出構(gòu)造器收到的異常信息,e.toString()輸出異常名稱與構(gòu)造器收到的異常信息尘执,e.printStackTrace();除兩者外還顯示異常代碼的位置舍哄。
  • e.printStackTrace();方法默認(rèn)會通過System.err將錯誤發(fā)送給標(biāo)準(zhǔn)錯誤流,e.printStackTrace(System.out);會將信息發(fā)送給輸出流誊锭。
  • 在catch塊中我們可以重新拋出異常表悬,但調(diào)用者需要使用throws來聲明。

代碼演示

class SimpleException extends Exception {
    public SimpleException() {}
    public SimpleException(String msg) {
        super(msg);
    }
}
public class ExceptionDemo {
    public void func() throws SimpleException {
        System.out.println("從func()拋出異常丧靡!");
        throw new SimpleException();
    }

    public void func1() throws SimpleException {
        System.out.println("從func1()拋出異常蟆沫!");
        throw new SimpleException("func1異常");
    }

    public static void main(String[] args) throws SimpleException {
        ExceptionDemo me = new ExceptionDemo();
        try {
            me.func();
        } catch (SimpleException e) {
            System.out.println("拋出異常籽暇!");
            e.printStackTrace();
        }

        try {
            me.func1();
            System.out.println("錯誤已引發(fā),此處不執(zhí)行");
        } catch (SimpleException e) {
            System.out.println(e.getMessage());
            System.out.println(e.toString());
            e.printStackTrace(System.out);
            throw e;//重新拋出異常
        }
    }
}

catch中拋出異常

  • 記錄異常后重新拋出異常:

    try{
      //可能存在異常的代碼
    }catch(Exception e){
      logger.log(level,message,e);
      throw e;
    }
    
  • 拋出新異常

    void func() throws ServletException {
      try {
          //可能存在異常的代碼
      } catch (Exception e) {//細(xì)化異常饭庞,重新拋出新異常
          Exception se = ServletException("database error");
              se.initCause(e);
          throw se;
              //Exception e =se.getCause(); //還原舊異常
      }
    }
    

異常使用技巧

  • 異常處理不能代替簡單的測試戒悠,比如說退棧操作不要異常處理
  • 不要過分的細(xì)化異常:盡量使用少的try舟山,catch完成工作
  • 利用異常層次結(jié)構(gòu)绸狐,拋出合理異忱鄣粒或自定義異常寒矿;不要只拋出RuntimeException或者Throwable
  • 不要壓制異常

關(guān)于斷言與日志記錄若债,后續(xù)學(xué)習(xí)符相!

本人小白一個蠢琳,歡迎訪問我的個人博客主巍,同時也歡迎來相互交流學(xué)習(xí)挪凑!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逛艰,一起剝皮案震驚了整個濱河市躏碳,隨后出現(xiàn)的幾起案子散怖,更是在濱河造成了極大的恐慌菇绵,老刑警劉巖镇眷,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咬最,死亡現(xiàn)場離奇詭異,居然都是意外死亡欠动,警方通過查閱死者的電腦和手機(jī)永乌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來具伍,“玉大人翅雏,你說我怎么就攤上這事∪搜浚” “怎么了望几?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長萤厅。 經(jīng)常有香客問我橄抹,道長靴迫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任楼誓,我火速辦了婚禮,結(jié)果婚禮上慌随,老公的妹妹穿的比我還像新娘芬沉。我一直安慰自己,他們只是感情好阁猜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布丸逸。 她就那樣靜靜地躺著,像睡著了一般剃袍。 火紅的嫁衣襯著肌膚如雪黄刚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天民效,我揣著相機(jī)與錄音憔维,去河邊找鬼。 笑死畏邢,一個胖子當(dāng)著我的面吹牛业扒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舒萎,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼程储,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了臂寝?” 一聲冷哼從身側(cè)響起章鲤,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咆贬,沒想到半個月后败徊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掏缎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年皱蹦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片御毅。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡根欧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出端蛆,到底是詐尸還是另有隱情凤粗,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站嫌拣,受9級特大地震影響柔袁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜异逐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一捶索、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灰瞻,春花似錦腥例、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至要销,卻和暖如春构回,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疏咐。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工纤掸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浑塞。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓借跪,卻偏偏與公主長得像酌壕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仅孩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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