什麼情況下使用異常處理?

對於異常處理總是抓不住重點,到底什麼時候使用異常處理呢?

比如

很多文章里舉除數為0的例子,難道不是先判斷除數,再進行除法嗎,為什麼需要異常處理?

還有FileNotFoundException,難道不是先判斷文件是否存在,然後再進行文件訪問嗎?

我能想到的就是,多進程系統上,因為判斷和處理過程不是原子操作,所以在它們之間,量、狀態、環境有可能會被改變,所以需要捕獲異常,進行異常處理。

是上述這樣的原因嗎,使用異常處理的根本是多進程和非原子操作?

看教程和文章實在想不到根本,還望指教。

Exception handling - 維基

-------------------------------------------------2014-12-19-------------------------------------------------------------

謝謝回答,現在令我疑惑的不僅僅是問題本身了,為什麼20個答案卻包含著好幾種觀點?

總結幾種觀點:

1、異常處理可以替代c時代的errno這樣的錯誤處理方式,而且作用域並非全局,可以順著方法的調用一直向上,直到被捕獲處理,是一種語法糖樣的東西,而且有一種面向對象的樣子。

2、因為底層API要拋異常,不try/catch程序就掛掉。(這不算回答本問題,但開發中往往就是這樣。當然僅try/catch不能囊括異常處理,還應該有throw等概念)

3、上述所說的多線程和非原子操作。(但現在意識到貌似這並非根本原因,甚至原因都算不上)

4、異常處理主要目地是為了強制方法調用者處理可能發生的錯誤。(應該用斷言,這種看法自認為是錯誤的)

5、不要用異常處理,應該使用狀態返回值。(額)

6、如果使用if/else,要很多的判斷,但是try/catch很簡單。

相關問題:

對使用 C++ 異常處理應具有怎樣的態度? - 編程

Swift 為什麼沒有異常處理? - 編程語言


通常情況下,使用者(包括用戶、代碼庫的使用者)所引發的錯誤,需要通過異常機制來處理

因為異常發生的時候,原訂的執行流程就無法繼續,但對於用戶來講,他們不能因為這樣的錯誤就終止程序的使用,所以提供給程序設計者異常機制,讓設計者決定發生意外的時候應該做些什麼。而這種意外的產生原因是用戶,用戶的操作千千萬萬,導致的結果也可能千奇百怪,但是他們的操作若使得原有流程無法繼續,那麼就是異常。

樓主說的判斷文件先存在,再讀寫文件,其實就是這個問題,按照程序的流程,可以保證在判斷是否存在的時候,文件的存在性,但是不能保證在真正操作文件的時候文件的存在性(例如判斷的時候文件還在,真正操作之前卻被用戶自己刪掉了)。因為流程上無法對流程外的用戶行為(用戶刪文件)作出保證,所以需要異常機制。

我認為,用戶在程序運行時觸發所導致的錯誤,需要異常機制來捕捉和處理。

程序設計中還有一種叫斷言(ASSERT)的東西,這種機制是用來約束程序設計者的,例如某些庫的某些函數,在文檔中約定了,這個函數的參數必須是&>0,那麼你在編程的時候愣是硬生生輸入一個0,那麼這時候就應該選擇斷言,用於幫助程序設計者及早的發現自己程序中的錯誤(這種錯誤是設計上的錯誤所引發的,而非用戶的操作所導致的),而不是用異常機制去處理。

所以,由程序員設計不足所導致的錯誤,需要用斷言來捕捉和處理。


簡單說就是,函數無法滿足調用方的期望的時候使用異常。

放在現實場景中就是,當上級交待給你的任務無法完成的時候,使用異常。

異常的目的是將這個問題傳遞給調用方解決。

就像在現實環境中,搞不定的時候找老闆一樣。


是啊,你先判斷除數,再進行觸發,那麼你在if (a == 0)這個分支里準備寫什麼?

// 看了評論發現初學者真是好多好多……


非原子操作的情況下,都可以插入其他的操作。

就下面兩步:

判斷文件存在

讀文件

如果有個程序在外部執行,在你的代碼做出判斷之後,把文件刪除了。

那麼一定會有Exception出現。

所以,該用就用。


我覺得相對於事先判斷異常並處理大概主要有 3 個方面的優點:

1、增強代碼的魯棒性而不必影響程序的主邏輯,使程序員專註於程序的主邏輯,保持代碼的簡潔清晰;

2、一些低調用級別的代碼塊沒有判斷和處理其上級調用模塊的許可權或者根本無法判斷,只能由其上級調用模塊來決定下一步怎麼做,這時當前模塊可以不用處理,將錯誤拋出給調用者;

3、對於異常的判斷是就地實時的,也就是與代碼運行是實時的,而事先判斷精確來講其實是提前的,這樣就不一定能準確地發現異常。


當前函數無法將某種狀態傳遞到外面的時候就要用異常處理。如果你用返回值或者某個參數作為函數成功與否的標誌,就沒有必要用了。


你想想什麼時候if..else 代替不了 try...catch


圖靈社區 : 圖書 : 2.5 異常處理

你寫了一個底層函數,出了錯誤,要return,這時候要定義好return的錯誤類型,

return error(0) if 0

return error(1) if 1

return error(2) if 2

return error(3) if 3

return error(4) if 4

return error(5) if 5

那麼在上一級調用的時候,又要根據值來判斷返回什麼,又要定義一堆if。

每調用一層就要定義一堆error信息

這樣不累嗎,出錯了直接拋個異常出去,不要管上面哪一層來捕獲處理,反正我就是拋了。

我拋的是個具體的異常。

至於頂上程序怎麼把這些異常分類處理,我就不管了。

誰調用誰處理,不處理就崩潰了


如果你能保證你的所有數據都有 transactionally roll back 能力,就可以。實際上,除非你的所有的數據都是簡單的純內存數據和 relational DB,是不可能的。

所以不要用異常。


你給的鏈接里也提到了,對於C++, Java, Python和Ruby來說,Exception的一大作用就是用來改變程序的control flow。比如說你自己寫的a()調用b(), b()調用c()....y()調用z(),z()throw一個FileNotFoundException就可以直接從這麼多層的stack里return回來。否則,你就要讓a...z都要對每一次調用檢查是否返回了錯誤代碼。


樓主混淆了設計和調用。設計一個除法必須考慮熊孩子把除數誤設為0的情況,調用者在調用前自然得保證除數不為0。所以前者需要一個異常後者不需要。


你無法事先知道這個程序有可能出什麼問題

同時你又不想使你的程序讓用戶看起來很爛

那麼 try 吧


一個方法需要做一些事情,滿足調用者的期望。但存在一些情況,使得這個方法不能滿足調用者期望、或無法理解調用者期望的時候,需要讓調用者知道這種情況的發生、也讓程序繼續運行下去,這就需要拋出異常了。如何處理這個異常,由調用者負責。

有時異常情況不一定需要使用語言的 exception 機制來實現,也可以返回「特殊值」,比如 IndexOf 返回 -1 表示找不到、ReadText 返回 null string 表示讀文件錯誤(而 empty string 才表示文件沒內容)。這種情況文檔需要清楚寫明。

不要捕獲那些你修復不了的異常。對於這種異常,最多用更好的描述重新拋出這個異常。程序拋出異常,不代表程序員犯錯。如果一個團隊不能正確理解異常處理,後果是災難性的。大量的返回類型是 void 的方法通常只有 if 而沒有 else,它的編寫者為自己的代碼沒有任何運行時錯誤輸出而自豪;調用者看不到任何錯誤,他認為那些方法正確的執行了自己的功能。然後調用者編寫的代碼就出錯了,他受到批評:「你應該處理異常情況」。於是調用者學乖了,開始和其他人一樣寫出大量的小心翼翼的 if。最後,整個系統沒有一行錯誤輸出,「完美無 bug」。這個脆弱的系統輸出任何非期望的結果時,沒有人知道那些成百上千的的 if 里是哪一條命中了;他們能做的,就是從輸出代碼開始緩慢的、一步步向下爬。


異常處理機制是語言或框架向你報告錯誤的途徑,不用它你就無法捕獲錯誤。

但是,不要在你自己的代碼里使用這種機制向上傳遞錯誤,雖然有異常處理的代碼,比沒有的要好很多,但作為一個企業級/強健壯性的高手來說,異常處理依然存在很多問題,不要用,舉個最簡單的例子,它無法精確記錄問題產生的位置。你應該使用與業務緊密相關的返回多狀態值的方法來進一步提高健壯性。

至於你說的判斷文件在不在,然後刪除,這顯然是簡單的並行編程中的入門事務性問題。答案大家都知道,老夫就不啰嗦了。


不大理解其它語言,我只知道java的,不過看樓主說的 FileNotFoundException 樓主應該問的也是java的?

java的異常都是Throwable派生出來的,主要是2大類Error和Exception.Error是我們無法處理的異常,一般發生了會導致JVM終止比如OutOfMemoryError,現在回到我們可以處理的就是Exception,樓主所關心的什麼情況下處理異常,Exception 又分2大類,一類是RuntimeException常見的NullPointException,ArayIndexOutOfBoundsException,ClassNotFoundException等等,其實這裡我也覺得你程序員應該避免發生RuntimeException,你代碼夠健壯你真不用處理,當然如果你可以預見可能會出現一些RuntimeException同時你也有後備方案那你當然可以處理。第二類比如樓主說的FileNotFoundException這種不是RuntimeException屬於可查異常,沒有為什麼,java編譯器在編譯的時候就要求你 必!須!處!理! 要麼try catch 要麼往上層拋


使用異常可以把錯誤處理代碼和正常的業務處理代碼區別開,便於開發和維護。這樣更好地體現了面向對象的思想。

你現在只是不希望被除數是0,在程序中加了個if語句,改天又有其他的限制,繼續加if else,將來程序龐大了之後,


異常處理主要目地是為了強制方法調用者處理可能發生的錯誤(已檢查異常)。你說的判斷是否為0,如果方法調用者忘了判斷返回值咋辦?已檢查異常就是干這個的!


個人體會最深的就是連接資料庫時是沒辦法判斷sql語句執行情況的,出錯時全憑異常處理捕獲異常信息


舉個抽象的例子,走迷宮走到錯路,你是選擇一步一步return回原點(好比你一個一個判斷錯誤情況,嗯,父函數可能也要相應處理),還是什麼都不管直接用秘籍(丟個異常)回到原點(你catch的地方)重新來過。


我覺的異常機制的出現

1,對於可預測的異常情況,像被除數為0 是可以用if、else的

使用exception是為了,讓if/else 純粹的去操作業務邏輯 ,不會應為過多的邏輯分支影響代碼的可讀性和可維護。

2,對於不可預測的異常情況,比如讀取文件,序列化對象,面對種種可能引發異常的情況。此時exception 提供了統一的處理方式。


推薦閱讀:

C# 中如何有效地釋放內存?
如何評價微軟推出的 .NET Native?
如何評價 JetBrains 將要推出的跨平台 C# IDE: Rider?
C#的Delegate 為什麼沒在其他主流語言中普及?
請問wpf在設計界面時,是使用blend可視化設計,還是直接編寫xaml代碼呢?

TAG:Java | C# | 異常處理 |