Android中的錯誤處理

讓我們來看一段有問題的代碼:

handler.sendMessageDelayed(msg, -1);

這個方法的作用是延遲一段時間之后姻灶,發(fā)送一條消息癌蚁。其中第一個參數(shù)msg是要發(fā)送的消息,第二個參數(shù)是延時的時間算行,單位是ms,按理來講這個延時的時間必須大于等于0苫耸。但是萬一其他人在調(diào)用的時候?qū)⑦@個參數(shù)傳進去一個負數(shù)州邢,比如-1,如果是你褪子,你會怎么處理這種情況量淌?

我們的代碼在運行的過程當中骗村,難免會出現(xiàn)一些錯誤,有開發(fā)人員人為導致的問題呀枢,比如除數(shù)為0叙身,傳進來一個空指針,或者某個人的年齡被設(shè)置為了負數(shù)硫狞,有些是外部原因信轿,比如正在讀取某個文件的時候,這個文件被刪了残吩,或者服務器給了你一個不存在的鏈接财忽。

采取哪種錯誤處理方式,取決于錯誤的產(chǎn)生原因和嚴重程度泣侮。

采用默認值

用我們剛才的例子來舉例即彪,handler.sendMessageDelayed的第二個參數(shù)不能為負數(shù),但是如果為負數(shù)活尊,源碼當中是這么處理的:

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

把小于0的輸入隶校,都當做0來處理。這是一種非常實用的處理方式蛹锰。我們平時就經(jīng)常用到這種方式深胳,只是可能沒有留意而已,比如SharedPreferences:

sharedPreferences.getString("username", "");

在獲取數(shù)據(jù)的時候铜犬,如果失敗舞终,則返回一個默認值,而不是null癣猾,會使得你的程序更加健壯并且更加優(yōu)雅敛劝。所以不要把第二個參數(shù)設(shè)置為null,因為如果設(shè)置為null的話纷宇,接下來又要有一個是否為null的判斷夸盟,白費了這個方法的設(shè)計者這樣設(shè)計的苦心。

斷言

Java提供了斷言機制像捶,采用assert關(guān)鍵字上陕。

assert s != null;

斷言就像是“活的”注釋,它告訴我們程序運行到這個地方的時候作岖,應該處于什么樣的狀態(tài)唆垃,或是滿足什么樣的條件。
需要特別說明一下痘儡,如果你在Android Studio中使用assert關(guān)鍵字辕万,IDE會建議你這樣使用:

if (BuildConfig.DEBUG && s == null) throw new AssertionError();

因為用assert關(guān)鍵字來斷言有個缺陷,就是無論你是在Debug版本還是Release版本當中,這些斷言都無可避免的會被執(zhí)行渐尿,而如果我們采用了上面的寫法醉途,在Release版本中,這些斷言就不會存在了砖茸。
此外隘擎,Google的Guava庫當中,也有一些用來起到類似斷言功能的方法凉夯,推薦大家使用货葬。

Preconditions.checkNotNull();
Preconditions.checkArgument();
Preconditions.checkElementIndex();
Preconditions.checkState();
Preconditions.checkPositionIndex();
Preconditions.checkPositionIndexes();

運行時異常

在這里,有一種情況需要特別注意一下:

Thread thread = new Thread();
thread.start();
thread.start();

我們都知道劲够,一個線程是不能啟動兩次的震桶,如果開發(fā)人員啟動了兩次,這種錯誤該如何處理征绎?

程序員在編程過程當中人為導致的錯誤蹲姐,所以應該拋出運行時異常。實際上android源碼當中是這樣處理這個問題的:

public synchronized void start() {
    if (hasBeenStarted) {
         throw new IllegalThreadStateException("Thread already started");
    }

    ...
}

針對這類問題人柿,對應的解決辦法應該是避免多次啟動柴墩。

所有的運行時異常都應該從根源上去避免這個錯誤,而不是用try-catch代碼塊來捕獲這個異常凫岖。

忽略

有人可能會這么處理剛才線程被啟動兩次的問題:

public synchronized void start() {
    if (hasBeenStarted) {
        return;
    }

    ...
}

如果這個線程已經(jīng)被啟動江咳,則返回,什么都不做隘截。這種做法有一定的缺陷扎阶,它在一定程度上放任了開發(fā)人員犯錯誤,同時它也有好處婶芭,我們來看另外一個例子:

public void close() throws IOException {
    synchronized (closeLock) {
        if (closed) {
            return;
        }
        closed = true;
    }
    ...
}

FileOutputStream的close方法就是這么做的,它忽略了多次調(diào)用着饥。如果有兩種情況下犀农,都需要關(guān)閉流,那么這樣可以省掉一些繁瑣的判斷宰掉。建議在線程啟動呵哨、文件流打開的時候要嚴格限制只允許調(diào)用一次,而停止或者關(guān)閉的操作允許多次調(diào)用轨奄,因為一般停止和關(guān)閉這類操作都不止一處需要調(diào)用孟害,至少有正常關(guān)閉和程序執(zhí)行過程中遇到異常關(guān)閉兩種,所以在關(guān)閉的時候不要限制那么嚴格也是有好處的挪拟。

非運行時異常

人們對非運行時異常褒貶不一挨务,大家爭論的地方主要在于非運行時異常必須得處理,而且它讓代碼變得很難看。一行代碼變成了四行之外谎柄,還多了一層縮進丁侄。結(jié)果就是哪里出現(xiàn)非運行時異常,哪里的代碼就會丑爆了朝巫。那么何時該使用非運行時異常鸿摇,一般來說,非運行時異常都是可以恢復的劈猿。

非運行時異常的優(yōu)點

強制程序員去處理出錯的情況拙吉。如果不強制大家去處理這個情況,很多人都會選擇不處理異常揪荣,比如下面的方法:

file.delete();

這個方法是有一個返回值的筷黔,返回true表示刪除成功,false表示刪除失敗变逃,這里必逆,沒有拋出非運行時異常,所以很多人都會閉上眼睛假裝不會失敗揽乱,導致程序不穩(wěn)定名眉。

非運行時異常的缺點

  • 那些發(fā)生概率極低或者明知道不會發(fā)生問題的地方,也必須要捕獲異常凰棉。
    比如下面的代碼:
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

這段代碼丑陋的地方在于损拢,這個線程,我根本不打算去執(zhí)行interrupt方法撒犀,sleep方法就根本不會拋出異常福压,catch代碼段根本不可能執(zhí)行到,或者即便拋異常了或舞,也沒什么大不了的荆姆,但是我們還是得去捕獲這個異常。Google也發(fā)現(xiàn)了這個問題映凳,所以給了大家另外一個選擇:

SystemClock.sleep(1000);
  • 一些設(shè)計的不好的異常胆筒,即便捕獲了,也無法處理诈豌。
try {
    JSONObject jsonObject = new JSONObject("");
} catch (JSONException e) {
    throw new RuntimeException(e);
}

比如這里的JSONException仆救,雖然它是非運行時異常,但是幾乎不可恢復矫渔,所以在catch代碼塊中也就只能再拋出一個運行時異常彤蔽。

總結(jié)

實際工作中遇到的情況各種各樣,但是一個總的原則就是通過分析錯誤的產(chǎn)生原因和嚴重程度來選擇處理錯誤的方式庙洼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顿痪,一起剝皮案震驚了整個濱河市镊辕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌员魏,老刑警劉巖丑蛤,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異撕阎,居然都是意外死亡受裹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門虏束,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棉饶,“玉大人,你說我怎么就攤上這事镇匀≌赵澹” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵汗侵,是天一觀的道長幸缕。 經(jīng)常有香客問我,道長晰韵,這世上最難降的妖魔是什么发乔? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮雪猪,結(jié)果婚禮上栏尚,老公的妹妹穿的比我還像新娘。我一直安慰自己只恨,他們只是感情好译仗,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著官觅,像睡著了一般纵菌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上休涤,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天产艾,我揣著相機與錄音,去河邊找鬼滑绒。 笑死,一個胖子當著我的面吹牛隘膘,可吹牛的內(nèi)容都是我干的疑故。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼弯菊,長吁一口氣:“原來是場噩夢啊……” “哼纵势!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤钦铁,失蹤者是張志新(化名)和其女友劉穎软舌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牛曹,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡佛点,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了黎比。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片超营。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖阅虫,靈堂內(nèi)的尸體忽然破棺而出演闭,到底是詐尸還是另有隱情,我是刑警寧澤颓帝,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布米碰,位于F島的核電站,受9級特大地震影響购城,放射性物質(zhì)發(fā)生泄漏吕座。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一工猜、第九天 我趴在偏房一處隱蔽的房頂上張望米诉。 院中可真熱鬧,春花似錦篷帅、人聲如沸史侣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惊橱。三九已至,卻和暖如春箭昵,著一層夾襖步出監(jiān)牢的瞬間税朴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工家制, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留正林,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓颤殴,卻偏偏與公主長得像觅廓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涵但,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理杈绸,服務發(fā)現(xiàn)帖蔓,斷路器,智...
    卡卡羅2017閱讀 134,715評論 18 139
  • error code(錯誤代碼)=0是操作成功完成瞳脓。error code(錯誤代碼)=1是功能錯誤塑娇。error c...
    Heikki_閱讀 3,390評論 1 9
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法劫侧,內(nèi)部類的語法埋酬,繼承相關(guān)的語法,異常的語法板辽,線程的語...
    子非魚_t_閱讀 31,665評論 18 399
  • 六種異常處理的陋習 你覺得自己是一個Java專家嗎奇瘦?是否肯定自己已經(jīng)全面掌握了Java的異常處理機制?在下面這段代...
    Executing閱讀 1,334評論 0 6
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,322評論 25 707