Java 異常體系規(guī)范

什么時(shí)候拋出異常(throw)

1、驗(yàn)證-拋出:當(dāng)程序檢測(cè)到非預(yù)期狀態(tài)、當(dāng)前處理層無法處理的,應(yīng)創(chuàng)建一個(gè)新的異常對(duì)象,并使用關(guān)鍵字throw,將異常拋給調(diào)用者

if (somethingIsInvalid) { 
    throw new SomeException("msg");
}

2、檢測(cè)-上拋:當(dāng)調(diào)用了一個(gè)聲明受檢異常的方法,當(dāng)前處理層無法處理,需要進(jìn)行適當(dāng)包裝的,應(yīng)創(chuàng)建一個(gè)異常封裝它,并使用關(guān)鍵字throw,將異常拋給調(diào)用者

} catch (SomeException se) { 
    throw new MethodDeclaredException(se);
}

3、re-throw: 當(dāng)調(diào)用了的方法拋出異常時(shí)(受檢或非受檢),根據(jù)情況可catch后進(jìn)行一定的處理,然后重新throw出去(或封裝一下再throw)

} catch (SomeException se) {
    doSomethingHere();  
    throw se; 
}

什么時(shí)候聲明異常(throws)

1、受檢異常必須聲明,非受檢異常可不必聲明

public void doSomething() throws ResourceFailureException {

2、目的:明確告知調(diào)用者可能拋出哪些異常;JavaDoc也可對(duì)該異常進(jìn)行說明使API更加友善
finally的使用
使用一個(gè)底層資源時(shí),完成任務(wù)后必須主動(dòng)關(guān)閉它。關(guān)閉的目的可能是釋放計(jì)算機(jī)某種設(shè)備、網(wǎng)絡(luò)、也可能是改變資源的狀態(tài)將之歸還給管理者等。
必須做的事情,在try-finally塊的finally中完成,每關(guān)閉一個(gè)資源應(yīng)單獨(dú)再做一次try-catch:

Resource resource = null; 

try {   
    resource = loadResource();  
    return doSomething(resource); 
} finally {
    if (resource != null) {
        try { 
            resource.close();
        } catch (Exception ex) {         
            logger.error("", ex);  
        } 
    } 
}

什么時(shí)候catch異常
使用

try {     
    execute(); 
} catch (SomeExceptin se) {  
    handlerSomeException(se); 
}

可以保證當(dāng)try中的語句發(fā)生SomeException異常的時(shí)候能夠執(zhí)行 handlerSomeException() 方法。 使用catch語句,使execute拋出的SomeException異常不會(huì)中斷整個(gè)調(diào)用,而所謂中斷就意味著一種無法處理的崩潰。 如果調(diào)用者"懂得"如何處理一個(gè)異常、能夠正確地調(diào)用后續(xù)的流程,則應(yīng)該堅(jiān)決使用catch語句捕獲它以完成業(yè)務(wù)。 如果 execute() 可拋出多種異常,調(diào)用者對(duì)不同的異??梢杂胁煌臉I(yè)務(wù)流程時(shí),應(yīng)該分別catch,不能僅僅只是catch 住一個(gè)普通的基類異常。

異常的日志輸出
對(duì)于可預(yù)知的或者已經(jīng)處理的異常,可以根據(jù)業(yè)務(wù)需要不輸出日志,或者輸出簡單日志,例如:

try {    
    getUserInfo(userId);
} catch (TimeoutException e) {    
    //deal with e  
    logger.error("UserInfo timeout:" + userId);
}

而對(duì)于那些不可預(yù)知的,或者捕獲后未做任何處理的異常,則最好將異常信息輸出,以方便調(diào)試,例如:

try {    
    doSomething();
} catch (Exception e) {
    //OR e.printStackTrace();
    logger.error("", e);    
}

注意:捕獲異常后不處理也不輸出log是一種非常不負(fù)責(zé)任的行為,這會(huì)造成問題很難被定位,極大地提高debug成本!

checked異常和unchecked異常的區(qū)別

checked異常
checked異常是指那些直接繼承自Exception的異常,如果一個(gè)方法聲明要拋出某種或者某幾種checked異常,那么此方法的調(diào)用者必須顯式地處理這些異常,或者也聲明要拋出這些異常,否則,代碼將無法編譯通過。例如:

//方法foo聲明可能會(huì)拋出IOException

public void foo() throws IOException {
    if (somethingIsInvalid) {
        throw new IOException();    
    }
}

 
//方法bar1調(diào)用foo,它需要處理foo拋出的IOException
public void bar1() {
    try {
        foo();    
    } catch (IOException e) {        
        //deal with e    
    }
}

 
//方法bar2調(diào)用foo,但是它無法處理foo拋出的IOException,則聲明自己也會(huì)拋出
//IOException,將異常丟給更上層的調(diào)用者來處理
public void bar2() throws IOException { 
    foo();
}

unchecked異常
unchecked異常是指那些直接繼承自RuntimeException的異常(比較特殊的是RuntimeException也是Exception的子類),它通常是由程序運(yùn)行時(shí)的錯(cuò)誤引起的,由于編譯器并不強(qiáng)制要求程序必須處理RuntimeException,所以叫unchecked異常。unchecked異常經(jīng)典例子是除0或者空指針:

public int divide(int n, int val) {
    if (val == 0) {
        throw new ArithmeticException("/ by zero");
    }
    
    return n / val;
}

public void foo(String s) {

    if (s == null) {
        throw new NullPointerException();
    }

    System.out.println(s);
}

微妙的區(qū)別
通過定義,很容易區(qū)分checked異常和unchecked異常,但是對(duì)于coder來說,在設(shè)計(jì)自定義異常的時(shí)候,何時(shí)使用checked異常,何時(shí)使用unchecked異常,的確是一個(gè)很微妙的話題。一般來講,checked異常是和具體應(yīng)用邏輯相關(guān)的異常,如文件沒有找到(FileNotFoundException),這些異常總可能發(fā)生,難以避免,并且底層邏輯希望由上層邏輯來處理這些異常情況,于是底層邏輯聲明要拋出一個(gè)checked異常。而unchecked異常通常用來表示那些程序運(yùn)行時(shí)發(fā)生的錯(cuò)誤,這些錯(cuò)誤通常有希望通過程序來避免,例如:NullPointerException可以通過程序判斷

if (ref != null) {
    goAhead();
} else {
    stop();
}

來避免。 也就是說unchecked異常存在的價(jià)值更傾向于幫助程序員發(fā)現(xiàn)程序中的錯(cuò)誤和不夠嚴(yán)謹(jǐn)?shù)倪壿嫞⑶倚迯?fù)這些問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,767評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評(píng)論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評(píng)論 2 375

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