1.錯誤處理--錯誤碼與捕獲異常

一般而言,對于錯誤處理,可以將其進行異常捕獲(try-catch)和通過返回錯誤碼這兩種方式。

有人說,對于一些偏底層的錯誤,比如:空指針、內(nèi)存不足等,可以使用返回錯誤狀態(tài)碼的方式,而對于一些上層的業(yè)務(wù)邏輯方面的錯誤,可以使用異常捕捉。這么說有一定道理,因為偏底層的函數(shù)可能用得更多一些。但是我并不這么認為。

因為,錯誤其實是很多的,不同的錯誤需要有不同的處理方式。但錯誤處理是有一些通用的規(guī)則的。為了講清這個事,我們需要把錯誤來分個類。我個人覺得錯誤可以被分成三個大類。

  • 資源的錯誤。當我們的代碼去請求一些資源時導(dǎo)致的錯誤,比如打開一個沒有權(quán)限的文件,寫文件時出現(xiàn)的寫錯誤,發(fā)送文件到網(wǎng)絡(luò)端發(fā)現(xiàn)網(wǎng)絡(luò)故障的錯誤,等等。這一類錯誤屬于程序運行環(huán)境的問題。對于這類錯誤,有的,我們可以處理,有的我們則無法處理。比如,內(nèi)存耗盡、棧溢出或是一些程序運行時關(guān)鍵性資源不能滿足時,我們只能停止運行,甚至退出整個程序
  • 程序的錯誤。比如:空指針、非法參數(shù)等。這類是我們自己程序的錯誤,我們要記錄下來,寫入日志,最好觸發(fā)監(jiān)控系統(tǒng)報警。
  • 用戶的錯誤。比如:Bad Request、Bad Format 等這類由用戶的不合法輸入帶來的錯誤。這類錯誤基本上是在用戶的 API 層上出現(xiàn)的問題。比如,解析一個 XML 或 JSon 文件,或是用戶輸入的字段不合法之類的。對于這類問題,我們需要向用戶端報錯,讓用戶自己處理修正他們的輸入或操作。然后,我們正常執(zhí)行,但是需要做統(tǒng)計,統(tǒng)計相應(yīng)的錯誤率,這樣有利我們改善軟件或是偵測是否有惡意的用戶請求。

我們可以看到,這三類錯誤中,有些是我們希望杜絕發(fā)生的,比如程序的 Bug,有些則是我們杜絕不了的,比如用戶的輸入。而對于程序運行環(huán)境中的一些錯誤,則是我們希望可以恢復(fù)的。也就是說,我們希望可以通過重試或是妥協(xié)的方式來解決這些環(huán)境的問題,比如重建網(wǎng)絡(luò)連接,重新打開一個新的文件。

所以,是不是我們可以這樣來在邏輯上分類:

  • 對于我們并不期望會發(fā)生的事,我們可以使用異常捕捉;
  • 對于我們覺得可能會發(fā)生的事,使用返回碼。

比如,如果你的函數(shù)參數(shù)傳入的對象不是一個 null 對象,那么,一旦傳入后,可以拋異常,因為我們并不期望總是會發(fā)生這樣的事。而對于一個需要檢查用戶輸入信息是否正確的事,比如:電子郵箱的格式,我們用返回碼可能會好一些。所以,對于上面三種錯誤的種類來說,程序中的錯誤,可能用異常捕捉會比較合適;用戶的錯誤,用返回碼比較合適;而資源類的錯誤,要分情況,是用異常捕捉還是用返回值,要看這事是不應(yīng)該出現(xiàn)的,還是經(jīng)常出現(xiàn)的。

當然,這只是一個大致的實踐原則,并不代表所有的事都需要符合這個原則。

除了用錯誤的分類來判斷是否用返回碼還是用異常捕捉之外,我們還要從程序設(shè)計的角度來考慮哪種情況下使用異常捕捉更好,哪種情況下使用返回碼更好。因為異常捕捉在編程上的好處比函數(shù)返回值好很多,所以很多使用異常捕捉的代碼會更易讀也更健壯一些。而返回碼容易被忽略,所以,使用返回碼的代碼需要做良好的測試才能得到更好的質(zhì)量。

不過,我們也要知道,在某些情況下,你只能使用其中的一個,比如:

  • 在 C++ 重載操作符的情況下,你就很難使用錯誤返回碼,只能拋異常;
  • 異常捕捉只能在同步的情況下使用,在異步模式下,拋異常這事就不行了,需要通過檢查子進程退出碼或是回調(diào)函數(shù)來解決;
  • 在分布式的情況下,調(diào)用遠程服務(wù)只能看錯誤返回碼,比如 HTTP 的返回碼。
    所以,在大多數(shù)情況下,我們會混用這兩種報錯的方式,有時候,我們還會把異常轉(zhuǎn)成錯誤碼(比如 HTTP 的 RESTful API),也會把錯誤碼轉(zhuǎn)成異常(比如對系統(tǒng)調(diào)用的錯誤)。

總之,“報錯的類型” 和 “錯誤處理” 是緊密相關(guān)的,錯誤處理方法多種多樣,而且會在不同的層面上處理錯誤。有些底層錯誤就需要自己處理掉(比如:底層模塊會自動重建網(wǎng)絡(luò)連接),而有一些錯誤需要更上層的業(yè)務(wù)邏輯來處理(比如:重建網(wǎng)絡(luò)連接不成功后只能讓上層業(yè)務(wù)來處理怎么辦?降級使用本地緩存還是直接報錯給用戶,等等)。所以,不同的錯誤類型再加上不同的錯誤處理會導(dǎo)致我們代碼組織層面上的不同,從而會讓我們使用不同的方式(也就是說,使用錯誤碼還是異常捕捉主要還是看我們我們的錯誤處理流程以及代碼組織怎么寫會更清楚)。

然而,這些知識和經(jīng)驗僅在同步編程世界中適用。因為在異步編程世界里,被調(diào)用的函數(shù)是被放到另外一個線程里運行的,所以本文中的兩位主角,不管是錯誤返回碼,還是異常捕捉,都難以發(fā)揮其威力。那么異步編程世界中是如何做錯誤處理的呢?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容