例如,您可以像考虑互斥体一样来考虑它。在关键部分内,您依靠多个语句来确保数据结构没有损坏并且其他线程无法看到您的中间值。如果这些语句中的任何一个没有随机运行,那么您最终会陷入一个痛苦的世界。现在去掉锁和并发,并像这样思考每个方法。如果愿意的话,可以将每个方法视为对象状态的排列事务。在方法调用开始时,对象应该处于干净状态,并且在结束时也应该处于干净状态。在这之间,变量 foo 可能与 bar 不一致,但您的代码最终会纠正这一点。例外意味着你的任何一个陈述都可以随时打断你。在每个单独的方法中,您有责任确保其正确并在发生这种情况时回滚,或者对您的操作进行排序,以便抛出不会影响对象状态。如果你弄错了(而且很容易犯这种错误),那么调用者最终会看到你的中间值。
整本书都是关于 C++ 中的异常安全编码的。很多专家都搞错了。如果它真的那么复杂并且有那么多细微差别,也许这是一个好兆头,表明您需要忽略该功能。 :-)
Exceptions make it really easy to write code where an exception being thrown will break invariants and leave objects in an inconsistent state. They essentially force you to remember that most every statement you make can potentially throw, and handle that correctly. Doing so can be tricky and counter-intuitive.
Consider something like this as a simple example:
class Frobber
{
int m_NumberOfFrobs;
FrobManager m_FrobManager;
public:
void Frob()
{
m_NumberOfFrobs++;
m_FrobManager.HandleFrob(new FrobObject());
}
};
Assuming the FrobManager will delete the FrobObject, this looks OK, right? Or maybe not... Imagine then if either FrobManager::HandleFrob() or operator new throws an exception. In this example, the increment of m_NumberOfFrobs does not get rolled back. Thus, anyone using this instance of Frobber is going to have a possibly corrupted object.
This example may seem stupid (ok, I had to stretch myself a bit to construct one :-)), but, the takeaway is that if a programmer isn't constantly thinking of exceptions, and making sure that every permutation of state gets rolled back whenever there are throws, you get into trouble this way.
As an example, you can think of it like you think of mutexes. Inside a critical section, you rely on several statements to make sure that data structures are not corrupted and that other threads can't see your intermediate values. If any one of those statements just randomly doesn't run, you end up in a world of pain. Now take away locks and concurrency, and think about each method like that. Think of each method as a transaction of permutations on object state, if you will. At the start of your method call, the object should be clean state, and at the end there should also be a clean state. In between, variable foo may be inconsistent with bar, but your code will eventually rectify that. What exceptions mean is that any one of your statements can interrupt you at any time. The onus is on you in each individual method to get it right and roll back when that happens, or order your operations so throws don't effect object state. If you get it wrong (and it's easy to make this kind of mistake), then the caller ends up seeing your intermediate values.
Methods like RAII, which C++ programmers love to mention as the ultimate solution to this problem, go a long way to protect against this. But they aren't a silver bullet. It will make sure you release resources on a throw, but doesn't free you from having to think about corruption of object state and callers seeing intermediate values. So, for a lot of people, it's easier to say, by fiat of coding style, no exceptions. If you restrict the kind of code you write, it's harder to introduce these bugs. If you don't, it's fairly easy to make a mistake.
Entire books have been written about exception safe coding in C++. Lots of experts have gotten it wrong. If it's really that complex and has so many nuances, maybe that's a good sign that you need to ignore that feature. :-)
如果你想知道为什么 Linus 认为异常是垃圾,最好的办法就是查找他关于该主题的著作。到目前为止,我唯一追踪到的就是嵌入在几封电子邮件中的这句话在 C++ 上:
“整个 C++ 异常处理从根本上来说已经被破坏了。对于内核来说尤其如此。”
您会注意到,他具体谈论的是 C++ 异常,而不是一般的异常。 (C++ 异常确实显然存在一些问题,使得它们很难正确使用。)
我的结论是,Linus 根本没有将异常(一般来说)称为“垃圾”!
The reason for Go not having exceptions is explained in the Go language design FAQ:
Exceptions are a similar story. A number of designs for exceptions have been proposed but each adds significant complexity to the language and run-time. By their very nature, exceptions span functions and perhaps even goroutines; they have wide-ranging implications. There is also concern about the effect they would have on the libraries. They are, by definition, exceptional yet experience with other languages that support them show they have profound effect on library and interface specification. It would be nice to find a design that allows them to be truly exceptional without encouraging common errors to turn into special control flow that requires every programmer to compensate.
Like generics, exceptions remain an open issue.
In other words, they haven't yet figured out how to support exceptions in Go in a way that they think is satisfactory. They are not saying that Exceptions are bad per se;
UPDATE - May 2012
The Go designers have now climbed down off the fence. Their FAQ now says this:
We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.
Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages.
Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient to handle catastrophe but requires no extra control structures and, when used well, can result in clean error-handling code.
See the Defer, Panic, and Recover article for details.
So the short answer is that they can do it differently using multi-value return. (And they do have a form of exception handling anyway.)
... and Linus of Linux fame has called exceptions crap.
If you want to know why Linus thinks exceptions are crap, the best thing is to look for his writings on the topic. The only thing I've tracked down so far is this quote that is embedded in a couple of emails on C++:
"The whole C++ exception handling thing is fundamentally broken. It's especially broken for kernels."
You'll note that he's talking about C++ exceptions in particular, and not exceptions in general. (And C++ exceptions do apparently have some issues that make them tricky to use correctly.)
My conclusion is that Linus hasn't called exceptions (in general) "crap" at all!
I disagree with "only throw exceptions in an exceptional situation." While generally true, it's misleading. Exceptions are for error conditions (execution failures).
Regardless of the language you use, pick up a copy of Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition). The chapter on exception throwing is without peer. Some quotes from the first edition (the 2nd's at my work):
DO NOT return error codes.
Error codes can be easily ignored, and often are.
Exceptions are the primary means of reporting errors in frameworks.
A good rule of thumb is that if a method does not do what its name suggests, it should be considered a method-level failure, resulting in an exception.
DO NOT use exceptions for the normal flow of control, if possible.
There are pages of notes on the benefits of exceptions (API consistency, choice of location of error handling code, improved robustness, etc.) There's a section on performance that includes several patterns (Tester-Doer, Try-Parse).
Exceptions and exception handling are not bad. Like any other feature, they can be misused.
Exceptions in and of themselves are not "bad", it's the way that exceptions are sometimes handled that tends to be bad. There are several guidelines that can be applied when handling exceptions to help alleviate some of these issues. Some of these include (but are surely not limited to):
Do not use exceptions to control program flow - i.e. do not rely on "catch" statements to change the flow of logic. Not only does this tend to hide various details around the logic, it can lead to poor performance.
Do not throw exceptions from within a function when a returned "status" would make more sense - only throw exceptions in an exceptional situation. Creating exceptions is an expensive, performance-intensive operation. For example, if you call a method to open a file and that file does not exist, throw a "FileNotFound" exception. If you call a method that determines whether a customer account exists, return a boolean value, do not return a "CustomerNotFound" exception.
When determining whether or not to handle an exception, do not use a "try...catch" clause unless you can do something useful with the exception. If you are not able to handle the exception, you should just let it bubble up the call stack. Otherwise, exceptions may get "swallowed" by the handler and the details will get lost (unless you rethrow the exception).
From the perspective of golang, I guess not having exception handling keeps the compiling process simple and safe.
From the perspective of Linus, I understand that kernel code is ALL about corner cases. So it makes sense to refuse exceptions.
Exceptions make sense in code were it's okay to drop the current task on the floor, and where common case code has more importance than error handling. But they require code generation from the compiler.
For example, they are fine in most high-level, user-facing code, such as web and desktop application code.
在这个问题上肯定没有达成共识。我想说,从像 Linus 这样的核心 C 程序员的角度来看,异常绝对是一个坏主意。然而,典型的 Java 程序员的情况却截然不同。
Typical arguments are that there's no way to tell what exceptions will come out of a particular piece of code (depending on language) and that they are too much like gotos, making it difficult to mentally trace execution.
There is definitely no consensus on this issue. I would say that from the point of view of a hard-core C programmer like Linus, exceptions are definitely a bad idea. A typical Java programmer is in a vastly different situation, though.
例外并不坏。它们非常适合 C++ 的 RAII 模型,这是 C++ 最优雅的地方。如果您已经有一堆不是异常安全的代码,那么它们在这种情况下就很糟糕。如果您正在编写非常低级的软件,例如 Linux 操作系统,那么它们就很糟糕。如果您喜欢在代码中添加大量错误返回检查,那么它们没有帮助。如果您没有抛出异常时的资源控制计划(C++ 析构函数提供),那么它们就很糟糕。
Exceptions aren't bad. They fit in well with C++'s RAII model, which is the most elegant thing about C++. If you have a bunch of code already that's not exception safe, then they're bad in that context. If you're writing really low level software, like the linux OS, then they're bad. If you like littering your code with a bunch of error return checks, then they not helpful. If you don't have a plan for resource control when an exception is thrown (that C++ destructors provides) then they're bad.
Say you are on a project and every controller (around 20 different major ones) extends a single superclass controller with an action method. Then every controller does a bunch of stuff different from each other calling objects B, C, D in one case and F, G, D in another case. Exceptions come to the rescue here in many cases where there was tons of return code and EVERY controller was handling it differently. I whacked all that code, threw the proper exception from "D", caught it in the superclass controller action method and now all our controllers are consistent. Previously D was returning null for MULTIPLE different error cases that we want to tell the end-user about but couldn't and I didn't want to turn the StreamResponse into a nasty ErrorOrStreamResponse object (mixing a data structure with errors in my opinion is a bad smell and I see lots of code return a "Stream" or other type of entity with error info embedded in it(it should really be the function returns the success structure OR the error structure which I can do with exceptions vs. return codes)....though the C# way of multiple responses is something I might consider sometimes though in many cases, the exception can skip a whole lot of layers(layers that I don't need to clean up resources on either).
yes, we have to worry about each level and any resource cleanup/leaks but in general none of our controllers had any resources to clean up after.
thank god we had exceptions or I would have been in for a huge refactor and wasted too much time on something that should be a simple programming problem.
Theoretically they are really bad. In perfect mathematical world you cannot get exception situations. Look at the functional languages, they have no side effects, so they virtually do not have source for unexceptional situations.
But, reality is another story. We always have situations that are "unexpected". This is why we need exceptions.
I think we can think of exceptions as of syntax sugar for ExceptionSituationObserver. You just get notifications of exceptions. Nothing more.
With Go, I think they will introduce something that will deal with "unexpected" situations. I can guess that they will try to make it sound less destructive as exceptions and more as application logic. But this is just my guess.
The exception-handling paradigm of C++, which forms a partial basis for that of Java, and in turn .net, introduces some good concepts, but also has some severe limitations. One of the key design intentions of exception handling is to allow methods to ensure that they will either satisfy their post-conditions or throw an exception, and also ensure that any cleanup which needs to happen before a method can exit, will happen. Unfortunately, the exception-handling paradigms of C++, Java, and .net all fail to provide any good means of handling the situation where unexpected factors prevent the expected cleanup from being performed. This in turn means that one must either risk having everything come to a screeching halt if something unexpected happens (the C++ approach to handling an exception occurs during stack unwinding), accept the possibility that a condition which cannot be resolved due to a problem that occurred during stack-unwinding cleanup will be mistaken for one which can be resolved (and could have been, had the cleanup succeeded), or accept the possibility that an unresolvable problem whose stack-unwinding cleanup triggers an exception that would typically be resolvable, might go unnoticed as code which handles the latter problem declares it "resolved".
Even if exception handling would generally be good, it's not unreasonable to regard as unacceptable an exception-handling paradigm that fails to provide a good means for handling problems that occur when cleaning up after other problems. That isn't to say that a framework couldn't be designed with an exception-handling paradigm that could ensure sensible behavior even in multiple-failure scenarios, but none of the top languages or frameworks can as yet do so.
For me the issue is very simple. Many programmers use exception handler inappropriately. More language resource is better. Be capable to handle exceptions is good. One example of bad use is a value that must be integer not be verified, or another input that may divide and not be checked for division of zero... exception handling may be an easy way to avoid more work and hard thinking, the programmer may want to do a dirty shortcut and apply an exception handling... The statement: "a professional code NEVER fails" might be illusory, if some of the issues processed by the algorithm are uncertain by its own nature. Perhaps in the unknown situations by nature is good come into play the exception handler. Good programming practices are a matter of debate.
I havent read all of the other answers, so this ma yhave already been mentioned, but one criticism is that they cause programs to break in long chains, making it difficult to track down errors when debugging the code. For example, if Foo() calls Bar() which calls Wah() which calls ToString() then accidentily pushing the wrong data into ToString() ends up looking like an error in Foo(), an almost completely unrelated function.
Okay, boring answer here. I guess it depends on the language really. Where an exception can leave allocated resources behind, they should be avoided. In scripting languages they just desert or overjump parts of the application flow. That's dislikable in itself, yet escaping near-fatal errors with exceptions is an acceptable idea.
For error-signaling I generally prefer error signals. All depends on the API, use case and severity, or if logging suffices. Also I'm trying to redefine the behaviour and throw Phonebooks() instead. The idea being that "Exceptions" are often dead ends, but a "Phonebook" contains helpful information on error recovery or alternative execution routes. (Not found a good use case yet, but keep trying.)
发布评论
评论(15)
异常使编写代码变得非常容易,其中抛出的异常将破坏不变量并使对象处于不一致的状态。它们本质上迫使您记住,您所做的大多数语句都可能会抛出异常,并正确处理它。这样做可能很棘手并且违反直觉。
考虑这样一个简单的例子:
假设
FrobManager
将删除
FrobObject
,这看起来不错,对吧?或者也许不是……想象一下,如果FrobManager::HandleFrob()
或operator new
抛出异常。在此示例中,m_NumberOfFrobs
的增量不会回滚。因此,任何使用Frobber
实例的人都将拥有一个可能已损坏的对象。这个例子可能看起来很愚蠢(好吧,我不得不花点力气来构造一个:-)),但是,要点是,如果程序员没有不断地考虑异常,并确保状态的每个排列都得到滚动每当有投掷的时候,你都会遇到麻烦。
例如,您可以像考虑互斥体一样来考虑它。在关键部分内,您依靠多个语句来确保数据结构没有损坏并且其他线程无法看到您的中间值。如果这些语句中的任何一个没有随机运行,那么您最终会陷入一个痛苦的世界。现在去掉锁和并发,并像这样思考每个方法。如果愿意的话,可以将每个方法视为对象状态的排列事务。在方法调用开始时,对象应该处于干净状态,并且在结束时也应该处于干净状态。在这之间,变量
foo
可能与bar
不一致,但您的代码最终会纠正这一点。例外意味着你的任何一个陈述都可以随时打断你。在每个单独的方法中,您有责任确保其正确并在发生这种情况时回滚,或者对您的操作进行排序,以便抛出不会影响对象状态。如果你弄错了(而且很容易犯这种错误),那么调用者最终会看到你的中间值。像 RAII 这样的方法(C++ 程序员喜欢将其称为此问题的最终解决方案)对于防止此问题大有帮助。但它们并不是灵丹妙药。它将确保您在抛出时释放资源,但不会让您不必考虑对象状态的损坏和调用者看到中间值。因此,对于很多人来说,根据编码风格,没有例外更容易说。如果您限制编写的代码类型,则更难引入这些错误。如果不这样做,就很容易犯错误。
整本书都是关于 C++ 中的异常安全编码的。很多专家都搞错了。如果它真的那么复杂并且有那么多细微差别,也许这是一个好兆头,表明您需要忽略该功能。 :-)
Exceptions make it really easy to write code where an exception being thrown will break invariants and leave objects in an inconsistent state. They essentially force you to remember that most every statement you make can potentially throw, and handle that correctly. Doing so can be tricky and counter-intuitive.
Consider something like this as a simple example:
Assuming the
FrobManager
willdelete
theFrobObject
, this looks OK, right? Or maybe not... Imagine then if eitherFrobManager::HandleFrob()
oroperator new
throws an exception. In this example, the increment ofm_NumberOfFrobs
does not get rolled back. Thus, anyone using this instance ofFrobber
is going to have a possibly corrupted object.This example may seem stupid (ok, I had to stretch myself a bit to construct one :-)), but, the takeaway is that if a programmer isn't constantly thinking of exceptions, and making sure that every permutation of state gets rolled back whenever there are throws, you get into trouble this way.
As an example, you can think of it like you think of mutexes. Inside a critical section, you rely on several statements to make sure that data structures are not corrupted and that other threads can't see your intermediate values. If any one of those statements just randomly doesn't run, you end up in a world of pain. Now take away locks and concurrency, and think about each method like that. Think of each method as a transaction of permutations on object state, if you will. At the start of your method call, the object should be clean state, and at the end there should also be a clean state. In between, variable
foo
may be inconsistent withbar
, but your code will eventually rectify that. What exceptions mean is that any one of your statements can interrupt you at any time. The onus is on you in each individual method to get it right and roll back when that happens, or order your operations so throws don't effect object state. If you get it wrong (and it's easy to make this kind of mistake), then the caller ends up seeing your intermediate values.Methods like RAII, which C++ programmers love to mention as the ultimate solution to this problem, go a long way to protect against this. But they aren't a silver bullet. It will make sure you release resources on a throw, but doesn't free you from having to think about corruption of object state and callers seeing intermediate values. So, for a lot of people, it's easier to say, by fiat of coding style, no exceptions. If you restrict the kind of code you write, it's harder to introduce these bugs. If you don't, it's fairly easy to make a mistake.
Entire books have been written about exception safe coding in C++. Lots of experts have gotten it wrong. If it's really that complex and has so many nuances, maybe that's a good sign that you need to ignore that feature. :-)
Go 没有异常的原因在 Go 语言设计 FAQ 中有解释:
换句话说,他们还没有弄清楚如何以他们认为满意的方式支持 Go 中的异常。他们并不是说异常本身就是不好的;而是说异常本身是不好的。
更新 - 2012 年 5 月
Go 设计师现在已经摆脱了栅栏。他们的常见问题解答现在是这样说的:
所以简短的答案是他们可以使用多值回报以不同的方式做到这一点。 (无论如何,他们确实有某种形式的异常处理。)
如果你想知道为什么 Linus 认为异常是垃圾,最好的办法就是查找他关于该主题的著作。到目前为止,我唯一追踪到的就是嵌入在几封电子邮件中的这句话在 C++ 上:
您会注意到,他具体谈论的是 C++ 异常,而不是一般的异常。 (C++ 异常确实显然存在一些问题,使得它们很难正确使用。)
我的结论是,Linus 根本没有将异常(一般来说)称为“垃圾”!
The reason for Go not having exceptions is explained in the Go language design FAQ:
In other words, they haven't yet figured out how to support exceptions in Go in a way that they think is satisfactory. They are not saying that Exceptions are bad per se;
UPDATE - May 2012
The Go designers have now climbed down off the fence. Their FAQ now says this:
So the short answer is that they can do it differently using multi-value return. (And they do have a form of exception handling anyway.)
If you want to know why Linus thinks exceptions are crap, the best thing is to look for his writings on the topic. The only thing I've tracked down so far is this quote that is embedded in a couple of emails on C++:
You'll note that he's talking about C++ exceptions in particular, and not exceptions in general. (And C++ exceptions do apparently have some issues that make them tricky to use correctly.)
My conclusion is that Linus hasn't called exceptions (in general) "crap" at all!
异常本身并不坏,但如果您知道它们会经常发生,那么它们在性能方面可能会很昂贵。
经验法则是异常应该标记异常情况,并且不应使用它们来控制程序流。
Exceptions are not bad per se, but if you know they are going to happen a lot, they can be expensive in terms of performance.
The rule of thumb is that exceptions should flag exceptional conditions, and that you should not use them for control of program flow.
我不同意“只在特殊情况下抛出异常”。虽然总体上是正确的,但它具有误导性。例外情况是错误情况(执行失败)。
无论您使用哪种语言,请获取框架设计指南的副本:约定、可重用 .NET 库的习语和模式(第二版)。关于异常抛出的章节是无与伦比的。第一版的一些引用(第二版是我的工作):
有几页关于异常好处的注释(API 一致性、错误处理代码位置的选择、改进的稳健性等)。有一个关于性能的部分,其中包括多种模式(测试者-执行者、尝试-解析)。
异常和异常处理还不错。与任何其他功能一样,它们也可能被滥用。
I disagree with "only throw exceptions in an exceptional situation." While generally true, it's misleading. Exceptions are for error conditions (execution failures).
Regardless of the language you use, pick up a copy of Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition). The chapter on exception throwing is without peer. Some quotes from the first edition (the 2nd's at my work):
There are pages of notes on the benefits of exceptions (API consistency, choice of location of error handling code, improved robustness, etc.) There's a section on performance that includes several patterns (Tester-Doer, Try-Parse).
Exceptions and exception handling are not bad. Like any other feature, they can be misused.
异常本身并不是“坏”的,而是有时处理异常的方式往往是坏的。处理异常时可以应用一些准则来帮助缓解其中的一些问题。其中一些包括(但肯定不限于):
Exceptions in and of themselves are not "bad", it's the way that exceptions are sometimes handled that tends to be bad. There are several guidelines that can be applied when handling exceptions to help alleviate some of these issues. Some of these include (but are surely not limited to):
从golang的角度来看,我想没有异常处理可以使编译过程变得简单和安全。
从 Linus 的角度来看,我理解内核代码都是关于极端情况的。所以拒绝例外是有道理的。
如果可以将当前任务放在地板上,并且常见情况代码比错误处理更重要,则异常在代码中是有意义的。但它们需要编译器生成代码。
例如,它们适用于大多数高级、面向用户的代码,例如 Web 和桌面应用程序代码。
From the perspective of golang, I guess not having exception handling keeps the compiling process simple and safe.
From the perspective of Linus, I understand that kernel code is ALL about corner cases. So it makes sense to refuse exceptions.
Exceptions make sense in code were it's okay to drop the current task on the floor, and where common case code has more importance than error handling. But they require code generation from the compiler.
For example, they are fine in most high-level, user-facing code, such as web and desktop application code.
典型的论点是,无法判断特定代码段(取决于语言)会出现哪些异常,而且它们太像
goto
,因此很难在心理上跟踪执行情况。http://www.joelonsoftware.com/items/2003/10/13.html
在这个问题上肯定没有达成共识。我想说,从像 Linus 这样的核心 C 程序员的角度来看,异常绝对是一个坏主意。然而,典型的 Java 程序员的情况却截然不同。
Typical arguments are that there's no way to tell what exceptions will come out of a particular piece of code (depending on language) and that they are too much like
goto
s, making it difficult to mentally trace execution.http://www.joelonsoftware.com/items/2003/10/13.html
There is definitely no consensus on this issue. I would say that from the point of view of a hard-core C programmer like Linus, exceptions are definitely a bad idea. A typical Java programmer is in a vastly different situation, though.
例外并不坏。它们非常适合 C++ 的 RAII 模型,这是 C++ 最优雅的地方。如果您已经有一堆不是异常安全的代码,那么它们在这种情况下就很糟糕。如果您正在编写非常低级的软件,例如 Linux 操作系统,那么它们就很糟糕。如果您喜欢在代码中添加大量错误返回检查,那么它们没有帮助。如果您没有抛出异常时的资源控制计划(C++ 析构函数提供),那么它们就很糟糕。
Exceptions aren't bad. They fit in well with C++'s RAII model, which is the most elegant thing about C++. If you have a bunch of code already that's not exception safe, then they're bad in that context. If you're writing really low level software, like the linux OS, then they're bad. If you like littering your code with a bunch of error return checks, then they not helpful. If you don't have a plan for resource control when an exception is thrown (that C++ destructors provides) then they're bad.
因此,异常的一个很好的用例是……
假设您在一个项目中,每个控制器(大约 20 个不同的主要控制器)都使用操作方法扩展单个超类控制器。然后,每个控制器都会执行一系列彼此不同的操作,在一种情况下调用对象 B、C、D,在另一种情况下调用对象 F、G、D。在许多情况下,异常会发挥作用,因为有大量的返回代码,并且每个控制器都以不同的方式处理它。我修改了所有代码,从“D”抛出正确的异常,在超类控制器操作方法中捕获它,现在我们所有的控制器都是一致的。以前,D 对于多个不同的错误情况返回 null,我们想要告诉最终用户但不能,而且我不想将 StreamResponse 变成令人讨厌的 ErrorOrStreamResponse 对象(在我看来,将数据结构与错误混合在一起是一股难闻的味道,我看到很多代码返回一个“流”或其他类型的实体,其中嵌入了错误信息(它实际上应该是函数返回成功结构或我可以使用异常与返回代码执行的错误结构 但在很多情况下,异常可以跳过很多层(我不需要清理资源的层)。
)....虽然我有时可能会考虑使用 C# 方式进行响应, 我们必须担心每个级别和任何资源清理/泄漏,但总的来说,我们的控制器都没有任何资源可以清理,
感谢上帝,我们有例外,否则我会进行巨大的重构并在某些事情上浪费太多时间。这应该是一个简单的编程问题。
A great use-case for exceptions is thus....
Say you are on a project and every controller (around 20 different major ones) extends a single superclass controller with an action method. Then every controller does a bunch of stuff different from each other calling objects B, C, D in one case and F, G, D in another case. Exceptions come to the rescue here in many cases where there was tons of return code and EVERY controller was handling it differently. I whacked all that code, threw the proper exception from "D", caught it in the superclass controller action method and now all our controllers are consistent. Previously D was returning null for MULTIPLE different error cases that we want to tell the end-user about but couldn't and I didn't want to turn the StreamResponse into a nasty ErrorOrStreamResponse object (mixing a data structure with errors in my opinion is a bad smell and I see lots of code return a "Stream" or other type of entity with error info embedded in it(it should really be the function returns the success structure OR the error structure which I can do with exceptions vs. return codes)....though the C# way of multiple responses is something I might consider sometimes though in many cases, the exception can skip a whole lot of layers(layers that I don't need to clean up resources on either).
yes, we have to worry about each level and any resource cleanup/leaks but in general none of our controllers had any resources to clean up after.
thank god we had exceptions or I would have been in for a huge refactor and wasted too much time on something that should be a simple programming problem.
从理论上讲,它们确实很糟糕。在完美的数学世界中你不可能遇到异常情况。看看函数式语言,它们没有副作用,因此它们实际上没有异常情况的源代码。
但是,现实却是另一回事。我们总是会遇到“意想不到”的情况。这就是为什么我们需要例外。
我认为我们可以将异常视为 ExceptionSituationObserver 的语法糖。您只会收到异常通知。而已。
对于 Go,我认为他们会引入一些可以处理“意外”情况的东西。我可以猜测,他们会尝试使其听起来不像异常那样具有破坏性,而更像应用程序逻辑。但这只是我的猜测。
Theoretically they are really bad. In perfect mathematical world you cannot get exception situations. Look at the functional languages, they have no side effects, so they virtually do not have source for unexceptional situations.
But, reality is another story. We always have situations that are "unexpected". This is why we need exceptions.
I think we can think of exceptions as of syntax sugar for ExceptionSituationObserver. You just get notifications of exceptions. Nothing more.
With Go, I think they will introduce something that will deal with "unexpected" situations. I can guess that they will try to make it sound less destructive as exceptions and more as application logic. But this is just my guess.
C++ 的异常处理范例构成了 Java 和 .net 异常处理范例的部分基础,引入了一些好的概念,但也有一些严重的局限性。异常处理的关键设计意图之一是允许方法确保它们满足后置条件或抛出异常,并确保在方法退出之前需要进行的任何清理都会发生。不幸的是,C++、Java 和 .net 的异常处理范例都无法提供任何好的方法来处理意外因素阻止执行预期清理的情况。这反过来意味着,如果发生意外情况(处理堆栈展开期间发生的异常的 C++ 方法),我们必须冒着一切都戛然而止的风险,接受由于发生问题而无法解决的情况的可能性在堆栈展开清理期间,将被误认为是可以解决的问题(如果清理成功的话,本来可以解决),或者接受这样一种可能性:无法解决的问题,其堆栈展开清理触发了通常可以解决的异常,可能会发生未被注意到,因为处理后一个问题的代码声明它“已解决”。
即使异常处理通常很好,但如果异常处理范例未能提供良好的方法来处理在清理其他问题后发生的问题,那么将其视为不可接受也并非没有道理。这并不是说框架不能设计具有异常处理范例,即使在多次失败的情况下也可以确保明智的行为,但目前还没有任何顶级语言或框架可以做到这一点。
The exception-handling paradigm of C++, which forms a partial basis for that of Java, and in turn .net, introduces some good concepts, but also has some severe limitations. One of the key design intentions of exception handling is to allow methods to ensure that they will either satisfy their post-conditions or throw an exception, and also ensure that any cleanup which needs to happen before a method can exit, will happen. Unfortunately, the exception-handling paradigms of C++, Java, and .net all fail to provide any good means of handling the situation where unexpected factors prevent the expected cleanup from being performed. This in turn means that one must either risk having everything come to a screeching halt if something unexpected happens (the C++ approach to handling an exception occurs during stack unwinding), accept the possibility that a condition which cannot be resolved due to a problem that occurred during stack-unwinding cleanup will be mistaken for one which can be resolved (and could have been, had the cleanup succeeded), or accept the possibility that an unresolvable problem whose stack-unwinding cleanup triggers an exception that would typically be resolvable, might go unnoticed as code which handles the latter problem declares it "resolved".
Even if exception handling would generally be good, it's not unreasonable to regard as unacceptable an exception-handling paradigm that fails to provide a good means for handling problems that occur when cleaning up after other problems. That isn't to say that a framework couldn't be designed with an exception-handling paradigm that could ensure sensible behavior even in multiple-failure scenarios, but none of the top languages or frameworks can as yet do so.
对我来说这个问题很简单。许多程序员不恰当地使用异常处理程序。语言资源越多越好。能够处理异常是件好事。不良使用的一个例子是一个必须是未经验证的整数的值,或者另一个可能除以但不检查除零的输入...异常处理可能是避免更多工作和艰苦思考的一种简单方法,程序员可能想要走一条肮脏的捷径并应用异常处理...如果算法处理的某些问题本质上是不确定的,那么“专业代码永远不会失败”的说法可能是虚幻的。也许在未知的情况下,异常处理程序本质上是很好的发挥作用的。良好的编程实践是一个有争议的问题。
For me the issue is very simple. Many programmers use exception handler inappropriately. More language resource is better. Be capable to handle exceptions is good. One example of bad use is a value that must be integer not be verified, or another input that may divide and not be checked for division of zero... exception handling may be an easy way to avoid more work and hard thinking, the programmer may want to do a dirty shortcut and apply an exception handling... The statement: "a professional code NEVER fails" might be illusory, if some of the issues processed by the algorithm are uncertain by its own nature. Perhaps in the unknown situations by nature is good come into play the exception handler. Good programming practices are a matter of debate.
我还没有阅读所有其他答案,所以这可能已经被提及,但一个批评是它们会导致程序中断长链,使得在调试代码时很难追踪错误。例如,如果 Foo() 调用 Bar(),而 Bar() 又调用 Wah(),而 Wah() 又调用 ToString(),那么意外地将错误的数据推入 ToString() 中,最终看起来就像 Foo() 中的错误,这是一个几乎完全不相关的函数。
I havent read all of the other answers, so this ma yhave already been mentioned, but one criticism is that they cause programs to break in long chains, making it difficult to track down errors when debugging the code. For example, if Foo() calls Bar() which calls Wah() which calls ToString() then accidentily pushing the wrong data into ToString() ends up looking like an error in Foo(), an almost completely unrelated function.
好吧,无聊的答案就到这里。我想这实际上取决于语言。如果异常可能导致分配的资源落后,则应避免这种情况。在脚本语言中,它们只是放弃或超越应用程序流程的某些部分。这本身是令人讨厌的,但用例外来逃避近乎致命的错误是一个可以接受的想法。
对于错误信号,我通常更喜欢错误信号。一切都取决于 API、用例和严重性,或者日志记录是否足够。另外,我正在尝试重新定义行为并改为
抛出Phonebooks()
。这个想法是“异常”通常是死胡同,但“电话簿”包含有关错误恢复或替代执行路线的有用信息。 (尚未找到好的用例,但请继续尝试。)Okay, boring answer here. I guess it depends on the language really. Where an exception can leave allocated resources behind, they should be avoided. In scripting languages they just desert or overjump parts of the application flow. That's dislikable in itself, yet escaping near-fatal errors with exceptions is an acceptable idea.
For error-signaling I generally prefer error signals. All depends on the API, use case and severity, or if logging suffices. Also I'm trying to redefine the behaviour and
throw Phonebooks()
instead. The idea being that "Exceptions" are often dead ends, but a "Phonebook" contains helpful information on error recovery or alternative execution routes. (Not found a good use case yet, but keep trying.)