code

예외 처리가 나쁜 이유는 무엇입니까?

codestyles 2020. 9. 11. 08:02
반응형

예외 처리가 나쁜 이유는 무엇입니까?


Google의 Go 언어는 디자인 선택으로 예외가 없으며 Linux 명성의 Linus는 예외를 쓰레기라고 불렀습니다. 왜?


예외는 throw되는 예외가 불변을 깨고 객체를 일관성없는 상태로 남겨 두는 코드를 작성하는 것을 정말 쉽게 만듭니다. 그들은 본질적으로 당신이 만드는 대부분의 진술이 잠재적으로 던질 수 있고 올바르게 처리 할 수 ​​있다는 것을 기억하도록 강요합니다. 그렇게하는 것은 까다 롭고 직관적이지 않을 수 있습니다.

다음과 같은 것을 간단한 예로 고려하십시오.

class Frobber
{
    int m_NumberOfFrobs;
    FrobManager m_FrobManager;

public:
    void Frob()
    {
        m_NumberOfFrobs++;

        m_FrobManager.HandleFrob(new FrobObject());
    }
};

가정 FrobManager것이다 오른쪽이 외모 확인을? 아니면 아닐 수도 있습니다 ... 그렇다면 또는 예외가 발생하는 경우를 상상해보십시오 . 이 예에서 증분은 롤백되지 않습니다. 따라서이 인스턴스를 사용하는 사람 은 개체가 손상되었을 수 있습니다.deleteFrobObjectFrobManager::HandleFrob()operator newm_NumberOfFrobsFrobber

이 예제는 어리석은 것처럼 보일 수 있습니다 (좋아요, 하나를 구성하기 위해 약간의 노력을 기울여야했습니다 :-)).하지만, 프로그래머가 예외를 계속 생각하지 않고 상태의 모든 순열이 롤링되는지 확인하는 것이 중요합니다. 던질 때마다 이런 식으로 문제가 생깁니다.

예를 들어 뮤텍스를 생각하는 것처럼 생각할 수 있습니다. 중요 섹션 내에서 데이터 구조가 손상되지 않았는지 다른 스레드가 중간 값을 볼 수 없는지 확인하기 위해 여러 명령문에 의존합니다. 이러한 진술 중 하나가 무작위로 실행되지 않으면 고통의 세계에 빠집니다. 이제 잠금과 동시성을 제거하고 각 방법에 대해 그렇게 생각하십시오. 원하는 경우 각 방법을 객체 상태에 대한 순열 트랜잭션으로 생각하십시오. 메서드 호출을 시작할 때 개체는 깨끗한 상태 여야하고 마지막에는 깨끗한 상태 여야합니다. 그 사이에 변수 foo는 다음과 일치하지 않을 수 있습니다.bar, 그러나 코드는 결국 그것을 수정할 것입니다. 예외의 의미는 귀하의 진술 중 하나가 언제든지 귀하를 방해 할 수 있다는 것입니다. 각 개별 메서드에서 문제가 발생하면 문제가 발생하면 롤백하거나 작업을 주문하여 throw가 개체 상태에 영향을 미치지 않도록해야합니다. 잘못 이해하면 (그리고 이런 종류의 실수를하기 쉽습니다), 호출자는 결국 중간 값을 보게됩니다.

C ++ 프로그래머가이 문제에 대한 궁극적 인 해결책으로 언급하기를 좋아하는 RAII와 같은 메서드는이를 방지하기 위해 먼 길을갑니다. 그러나 그것들은 은총이 아닙니다. 던질 때 리소스를 해제 할 수는 있지만 객체 상태의 손상과 호출자가 중간 값을 보는 것에 대해 생각할 필요가 없습니다. 따라서 많은 사람들에게 코딩 스타일의 명목상 예외없다고 말하는 것이 더 쉽습니다 . 작성하는 코드의 종류를 제한하면 이러한 버그를 도입하기가 더 어렵습니다. 그렇지 않으면 실수하기가 매우 쉽습니다.

C ++의 예외 안전 코딩에 대해 전체 책이 작성되었습니다. 많은 전문가들이 잘못 알고 있습니다. 정말 그렇게 복잡하고 뉘앙스가 너무 많다면 그 기능을 무시해야한다는 좋은 신호일 수 있습니다. :-)


Go에 예외가없는 이유는 Go 언어 디자인 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:

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!


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.


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.


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.


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):

  1. 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.
  2. 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.
  3. 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).

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.

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.


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.


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.


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.


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.


  • Exception not being handled is generally bad.
  • Exception handled badly is bad (of course).
  • The 'goodness/badness' of exception handling depends on the context/scope and the appropriateness, and not for the sake of doing it.

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.)


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.

참고URL : https://stackoverflow.com/questions/1736146/why-is-exception-handling-bad

반응형