Android基礎(chǔ)進(jìn)階之EffectiveJava翻譯系列(第八章:異常)

高效使用異常指南

Item 57: Use exceptions only for exceptional conditions

只有在異常條件下才使用異常

考慮如下的代碼

//bad !! don't do this
try {
    int i = 0;
    while(true)
        range[i++].climb();
} catch(ArrayIndexOutOfBoundsException e){}

使用異常條件來終止遍歷操作是非常錯誤的做法

使用如下代碼代替

for (Mountain m : range)
    m.climb();

名副其實,異常只能用在異常條件下,而不能用于流程控制


Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors

對可恢復(fù)條件使用檢查異常蹬昌,對程序錯誤使用運行時異常犀盟。

Java提供了三種異常:checked exceptions,runtime exceptions and errors.大多數(shù)程序員對何時使用何種異常有困惑,有如下幾種原則作參考

決定使用檢查異常或非檢查異常的原則是:調(diào)用方可以合理的修復(fù)異常,現(xiàn)如今的IDE工具如eclipse或Android studio會自動提示此類異常,自動填充try catch

非檢查異常有兩種:runtime exceptions and errors

用運行時異常(runtime exceptions)識程序錯誤,絕大多數(shù)的運行時異常都表明違反了某種前提條件,如ArrayIn?dexOutOfBoundsException數(shù)組越界

有一個普遍的約定是error用于JVM,所以所有的非檢查異常都應(yīng)該繼承自 RuntimeException

常見的非檢查異常runtime exception

  • NullPointerException, 空指針異常
  • ArithmeticException, 算術(shù)異常
  • ClassCastException, 類型強(qiáng)制轉(zhuǎn)換異常
  • IllegalArgumentException, 傳遞非法參數(shù)異常

Item 59: Avoid unnecessary use of checked exceptions

避免過度使用檢查異常
如果一個方法有多個檢查異常,調(diào)用者會包裹多個catch來處理異常,這里沒有一個絕對的準(zhǔn)則,可以使用if語句把條件先過濾一遍而避免拋異常


Item 60: Favor the use of standard exceptions

使用常用異常
當(dāng)需要拋出一個異常時,盡量使用Java平臺提供好的異常,因為大家都知道什么意思


Item 61: Throw exceptions appropriate to the abstraction

拋出更合適的抽象異常

當(dāng)拋出和任務(wù)不相關(guān)的異常時容易讓人困惑,當(dāng)拋出一個低級的異常時,這種情況經(jīng)常發(fā)生,它不僅僅令人困惑,也污染了上層的調(diào)用

為了避免這個問題寒砖,上層應(yīng)該捕獲較低級別的異常谅猾,并在它們的位置上拋出可以用更高級別的抽象來解釋的異常,如:

// Exception Translation
try {
    // Use lower-level abstraction to do our bidding
    ...
} catch(LowerLevelException e) {
    throw new HigherLevelException(...);
}

更具體的例子在List<E>的方法中

/**
* Returns the element at the specified position in this list.
* @throws IndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()}).
*/
public E get(int index) {
    ListIterator<E> i = listIterator(index);
    try {
        return i.next();
    } catch(NoSuchElementException e) {
        throw new IndexOutOfBoundsException("Index: " + index);
    }
}

這種特殊的異常處理方式被稱為"異常鏈",但是也不應(yīng)該過度使用

我們也可以在在上層調(diào)用中拋出底層錯誤的原因

// Exception Chaining
try {
    ... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException cause) {
    throw new HigherLevelException(cause);
}

最好的方式還是盡量在底層避免異常,如果不能處理在考慮"異常鏈"的方式


Item 62: Document all exceptions thrown by each method

為每個方法拋出的異常添加文檔注釋

對于檢查異常,要說明前置條件,并用@throws標(biāo)記合適的異常,不要為了圖簡單直接 @throws Exception

如果一個異常被多個方法拋出,并且是相同的原因,則不要在方法上注釋,而是要在類上添加異常注釋


Item 63: Include failure-capture information in detail messages

打印出異常的詳細(xì)信息以便于分析


Item 64: Strive for failure atomicity

保證錯誤的原子性(調(diào)用一千次,輸出一樣)

即使一個異常發(fā)生了,我們也希望對象能正常使用

有幾種方式可以達(dá)到這一點,最簡單的就是創(chuàng)建不可變的對象,如果一個對象是不可變的,原子性也隨之而來

對于可變對象,常見的方式是檢查參數(shù)的合法性(Item 38)

第三種方式是發(fā)生異常后,回滾異常狀態(tài)為使用前的初始狀態(tài)

最后一種方式使用拷貝來避免發(fā)生錯誤時改變原來對象的狀態(tài),如Collections.sort,排序方法會先轉(zhuǎn)成array數(shù)組來排序,本來是為了提高性能,額外的如果發(fā)生了錯誤不會改變原集合的狀態(tài)

雖然原子性能保證,但是實際使用中并不總是能達(dá)到滿意的狀態(tài),如兩個線程同時修改一個對象,沒有同步的情況下,引發(fā)了currentModificationException.這時如果恢復(fù)對象的狀態(tài)依然不能使程序正確運行

作為一種規(guī)則來講,當(dāng)發(fā)生異常時總能確保當(dāng)前對象的狀態(tài),可惜目前很多API都沒有遵守


Item 65: Don’t ignore exceptions

不要忽略異常

這條建議看似很明顯,但是值得重復(fù),當(dāng)API的設(shè)計者聲明了一種異常,他們是為了告訴你什么,不要忽略它!很容易包裹一個空的try catch語句就不管這個異常了.如:

try {
    ...
} catch (SomeException e) {
}

空處理并不是拋異常的初衷,目的是為了強(qiáng)制解決這個異常條件.忽略異常就像忽略火警廣播,有人關(guān)了廣播導(dǎo)致其他人并不知道發(fā)生了火災(zāi).如果確實需要一個空的處理,需要詳細(xì)說明為何空處理是合適的


上一章:通用原則

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荐吵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赊瞬,更是在濱河造成了極大的恐慌先煎,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巧涧,死亡現(xiàn)場離奇詭異薯蝎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)谤绳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門占锯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缩筛,你說我怎么就攤上這事消略。” “怎么了瞎抛?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵艺演,是天一觀的道長。 經(jīng)常有香客問我桐臊,道長胎撤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任断凶,我火速辦了婚禮伤提,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘认烁。我一直安慰自己肿男,他們只是感情好介汹,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舶沛,像睡著了一般嘹承。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冠王,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天赶撰,我揣著相機(jī)與錄音,去河邊找鬼柱彻。 笑死豪娜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哟楷。 我是一名探鬼主播瘤载,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼卖擅!你這毒婦竟也來了鸣奔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤惩阶,失蹤者是張志新(化名)和其女友劉穎挎狸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體断楷,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锨匆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冬筒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恐锣。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖舞痰,靈堂內(nèi)的尸體忽然破棺而出土榴,到底是詐尸還是另有隱情,我是刑警寧澤响牛,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布玷禽,位于F島的核電站,受9級特大地震影響娃善,放射性物質(zhì)發(fā)生泄漏论衍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一聚磺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炬丸,春花似錦瘫寝、人聲如沸蜒蕾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咪啡。三九已至,卻和暖如春暮屡,著一層夾襖步出監(jiān)牢的瞬間撤摸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工褒纲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留准夷,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓莺掠,卻偏偏與公主長得像衫嵌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子彻秆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

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

  • 寫在最前 最近筆者在撰寫JavaWeb與自動化相結(jié)合的教程楔绞,上篇入口在這里,第二篇還在創(chuàng)作中唇兑,在發(fā)布之前酒朵,讓我們先...
    LightningDC閱讀 470評論 0 0
  • 《Effective Java》筆記(下) Enums and Annotations Item 30: Use ...
    OCNYang閱讀 2,039評論 1 5
  • 對象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法,而不是構(gòu)造函數(shù)創(chuàng)建對象:僅僅是創(chuàng)建對象的方法扎附,并非Fa...
    孫小磊閱讀 1,996評論 0 3
  • Creating and Destroying Objects Item 1: Consider static f...
    時間_77c1閱讀 385評論 0 0
  • 在詩畫中閉關(guān)蔫耽,在歲月中沉淀,關(guān)閉所有帕棉,靜音的模式生長针肥,一覺自然地醒來,二月的第一縷陽光香伴,照進(jìn)我的窗臺慰枕! 瑜伽禪樂中...
    百合_b1fc閱讀 169評論 0 0