問題描述
我經常看到/聽到人們說異常應該很少使用,但從不解釋原因.雖然這可能是真的,但基本原理通常是一個油嘴滑舌:它被稱為異常是有原因的",對我來說,這似乎是一種不應該被受人尊敬的程序員接受的解釋/工程師.
I often see/hear people say that exceptions should only be used rarely, but never explain why. While that may be true, rationale is normally a glib: "it's called an exception for a reason" which, to me, seems to be the sort of explanation that should never be accepted by a respectable programmer/engineer.
異常可用于解決一系列問題.為什么將它們用于控制流是不明智的?對它們的使用方式異常保守的背后的哲學是什么?語義?表現?復雜?美學?約定?
There is a range of problems that an exception can be used to solve. Why is it unwise to use them for control flow? What is the philosophy behind being exceptionally conservative with how they are used? Semantics? Performance? Complexity? Aesthetics? Convention?
我之前看過一些關于性能的分析,但在與某些系統相關而與其他系統無關的層面上.
I've seen some analysis on performance before, but at a level that would be relevant to some systems and irrelevant to others.
同樣,我不一定不同意它們應該在特殊情況下保存,但我想知道共識的基本原理是什么(如果存在這樣的事情).
Again, I don't necessarily disagree that they should be saved for special circumstances, but I'm wondering what the consensus rationale is (if such a thing exists).
推薦答案
主要的摩擦點是語義.許多開發人員濫用異常并抓住一切機會拋出它們.這個想法是在一些特殊情況下使用異常.例如,錯誤的用戶輸入不算作異常,因為您希望這會發生并為此做好準備.但是,如果您嘗試創建一個文件并且磁盤上沒有足夠的空間,那么是的,這是一個明顯的例外.
The primary point of friction is semantics. Many developers abuse exceptions and throw them at every opportunity. The idea is to use exception for somewhat exceptional situation. For example, wrong user input does not count as an exception because you expect this to happen and ready for that. But if you tried to create a file and there was not enough space on disk, then yes, this is a definite exception.
另一個問題是異常經常被拋出和吞下.開發人員使用這種技術來簡單地靜默"程序并讓它運行盡可能長的時間直到完全崩潰.這是非常錯誤的.如果你不處理異常,如果你沒有通過釋放一些資源來做出適當的反應,如果你沒有記錄異常發生或至少沒有通知用戶,那么你就沒有使用異常的含義.
One other issue is that exceptions are often thrown and swallowed. Developers use this technique to simply "silence" the program and let it run as long as possible until completely collapsing. This is very wrong. If you don't process exceptions, if you don't react appropriately by freeing some resources, if you don't log the exception occurrence or at least not notify the user, then you're not using exception for what they are meant.
直接回答你的問題.應該很少使用異常,因為異常情況很少見,而且異常代價高昂.
Answering directly your question. Exceptions should rarely be used because exceptional situations are rare and exceptions are expensive.
很少見,因為您不希望每次按下按鈕或每次輸入格式錯誤時程序都會崩潰.比如說,數據庫可能突然無法訪問,可能磁盤空間不足,您依賴的某些第三方服務離線,這一切都可能發生,但很少見,這些都是明顯的例外情況.
Rare, because you don't expect your program crash at every button press or at every malformed user input. Say, database may suddenly not be accessible, there may not be enough space on disk, some third party service you depend on is offline, this all can happen, but quite rarely, these would be clear exceptional cases.
昂貴,因為拋出異常會中斷正常的程序流程.運行時將展開堆棧,直到找到可以處理異常的適當異常處理程序.它還將在整個過程中收集調用信息以傳遞給處理程序將接收的異常對象.都是有代價的.
Expensive, because throwing an exception will interrupt the normal program flow. The runtime will unwind the stack until it finds an appropriate exception handler that can handle the exception. It will also gather the call information all along the way to be passed to the exception object the handler will receive. It all has costs.
這并不是說使用異常就沒有例外(微笑).有時,如果您拋出異常而不是通過多層轉發返回代碼,它可以簡化代碼結構.作為一個簡單的規則,如果您希望某個方法經常被調用并且在一半的時間里發現了一些異常"情況,那么最好找到另一個解決方案.但是,如果您希望大部分時間都可以正常運行,而這種異常"情況只會出現在極少數情況下,那么拋出異常就可以了.
This is not to say that there can be no exception to using exceptions (smile). Sometimes it can simplify the code structure if you throw an exception instead of forwarding return codes via many layers. As a simple rule, if you expect some method to be called often and discover some "exceptional" situation half the time then it is better to find another solution. If however you expect normal flow of operation most of the time while this "exceptional" situation can only emerge in some rare circumstances, then it is just fine to throw an exception.
@Comments:如果可以讓您的代碼更簡單、更容易,則絕對可以在一些不太例外的情況下使用異常.這個選項是開放的,但我想說它在實踐中很少見.
@Comments: Exception can definitely be used in some less-exceptional situations if that could make your code simpler and easier. This option is open but I'd say it comes quite rare in practice.
為什么將它們用于控制流是不明智的?
Why is it unwise to use them for control flow?
因為異常會破壞正常的控制流".您引發異常并放棄程序的正常執行,這可能會導致對象處于不一致狀態,并且某些開放資源未釋放.當然,C# 有 using 語句,它可以確保即使從 using 主體拋出異常,對象也會被釋放.但是讓我們暫時從語言中抽象出來.假設框架不會為您處理對象.你手動完成.你有一些關于如何請求和釋放資源和內存的系統.您在系統范圍內達成一致,誰負責在什么情況下釋放對象和資源.您有如何處理外部庫的規則.如果程序遵循正常的操作流程,則效果很好.但是在執行過程中突然你拋出一個異常.一半的資源沒有被釋放.一半還沒有被要求.如果該操作現在是事務性的,它就會被破壞.您處理資源的規則將不起作用,因為那些負責釋放資源的代碼部分根本不會執行.如果其他人想要使用這些資源,他們可能會發現它們處于不一致的狀態并崩潰,因為他們無法預測這種特定情況.
Because exceptions disrupt normal "control flow". You raise an exception and normal execution of the program is abandoned potentially leaving objects in inconsistent state and some open resources unfreed. Sure, C# has the using statement which will make sure the object will be disposed even if an exception is thrown from the using body. But let us abstract for the moment from the language. Suppose the framework won't dispose objects for you. You do it manually. You have some system for how to request and free resources and memory. You have agreement system-wide who is responsible for freeing objects and resources in what situations. You have rules how to deal with external libraries. It works great if the program follows the normal operation flow. But suddenly in the middle of execution you throw an exception. Half of the resources are left unfreed. Half have not been requested yet. If the operation was meant to be transactional now it is broken. Your rules for handling resources will not work because those code parts responsible for freeing resources simply won't execute. If anybody else wanted to use those resources they may find them in inconsistent state and crash as well because they could not predict this particular situation.
比如說,你想要一個方法 M() 調用方法 N() 來做一些工作并安排一些資源,然后將它返回給 M(),它會使用它然后處理它.美好的.現在 N() 中出了點問題,它在 M() 中拋出了一個您沒有預料到的異常,因此異常冒泡到頂部,直到它可能被某個方法 C() 捕獲,而 C() 將不知道在深處發生了什么在 N() 中以及是否以及如何釋放一些資源.
Say, you wanted a method M() call method N() to do some work and arrange for some resource then return it back to M() which will use it and then dispose it. Fine. Now something goes wrong in N() and it throws an exception you didn't expect in M() so the exception bubbles to the top until it maybe gets caught in some method C() which will have no idea what was happening deep down in N() and whether and how to free some resources.
通過拋出異常,您可以創建一種方法,使您的程序進入許多難以預測、理解和處理的新的不可預測的中間狀態.這有點類似于使用 GOTO.設計一個程序可以將其執行從一個位置隨機跳轉到另一個位置是非常困難的.它也很難維護和調試.當程序變得越來越復雜時,您只會失去對何時何地發生了什么事情的概覽,而無法修復它.
With throwing exceptions you create a way to bring your program into many new unpredictable intermediate states which are hard to prognose, understand and deal with. It's somewhat similar to using GOTO. It is very hard to design a program that can randomly jump its execution from one location to the other. It will also be hard to maintain and debug it. When the program grows in complexity, you just going to lose an overview of what when and where is happening less to fix it.
這篇關于為什么要保守地使用異常?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!