When to throw an exception?

2018-12-31 03:34发布

I have exceptions created for every condition that my application does not expect. UserNameNotValidException, PasswordNotCorrectException etc.

However I was told I should not create exceptions for those conditions. In my UML those ARE exceptions to the main flow, so why should it not be an exception?

Any guidance or best practices for creating exceptions?

30条回答
何处买醉
2楼-- · 2018-12-31 04:06

My little guidelines are heavily influenced by the great book "Code complete":

  • Use exceptions to notify about things that should not be ignored.
  • Don't use exceptions if the error can be handled locally
  • Make sure the exceptions are at the same level of abstraction as the rest of your routine.
  • Exceptions should be reserved for what's truly exceptional.
查看更多
还给你的自由
3楼-- · 2018-12-31 04:08

I think you should only throw an exception when there's nothing you can do to get out of your current state. For example if you are allocating memory and there isn't any to allocate. In the cases you mention you can clearly recover from those states and can return an error code back to your caller accordingly.


You will see plenty of advice, including in answers to this question, that you should throw exceptions only in "exceptional" circumstances. That seems superficially reasonable, but is flawed advice, because it replaces one question ("when should I throw an exception") with another subjective question ("what is exceptional"). Instead, follow the advice of Herb Sutter (for C++, available in the Dr Dobbs article When and How to Use Exceptions, and also in his book with Andrei Alexandrescu, C++ Coding Standards): throw an exception if, and only if

  • a precondition is not met (which typically makes one of the following impossible) or
  • the alternative would fail to meet a post-condition or
  • the alternative would fail to maintain an invariant.

Why is this better? Doesn't it replace the question with several questions about preconditions, postconditions and invariants? This is better for several connected reasons.

  • Preconditions, postconditions and invariants are design characteristics of our program (its internal API), whereas the decision to throw is an implementation detail. It forces us to bear in mind that we must consider the design and its implementation separately, and our job while implementing a method is to produce something that satisfies the design constraints.
  • It forces us to think in terms of preconditions, postconditions and invariants, which are the only assumptions that callers of our method should make, and are expressed precisely, enabling loose coupling between the components of our program.
  • That loose coupling then allows us to refactor the implementation, if necessary.
  • The post-conditions and invariants are testable; it results in code that can be easily unit tested, because the post-conditions are predicates our unit-test code can check (assert).
  • Thinking in terms of post-conditions naturally produces a design that has success as a post-condition, which is the natural style for using exceptions. The normal ("happy") execution path of your program is laid out linearly, with all the error handling code moved to the catch clauses.
查看更多
步步皆殇っ
4楼-- · 2018-12-31 04:08

In general you want to throw an exception for anything that can happen in your application that is "Exceptional"

In your example, both of those exceptions look like you are calling them via a password / username validation. In that case it can be argued that it isn't really exceptional that someone would mistype a username / password.

They are "exceptions" to the main flow of your UML but are more "branches" in the processing.

If you attempted to access your passwd file or database and couldn't, that would be an exceptional case and would warrant throwing an exception.

查看更多
倾城一夜雪
5楼-- · 2018-12-31 04:08

"PasswordNotCorrectException" isn't a good example for using exceptions. Users getting their passwords wrong is to be expected, so it's hardly an exception IMHO. You probably even recover from it, showing a nice error message, so it's just a validity check.

Unhandled exceptions will stop the execution eventually - which is good. If you're returning false, null or error codes, you will have to deal with the program's state all by yourself. If you forget to check conditions somewhere, your program may keep running with wrong data, and you may have a hard time figuring out what happened and where.

Of course, you could cause the same problem with empty catch statements, but at least spotting those is easier and doesn't require you to understand the logic.

So as a rule of thumb:

Use them wherever you don't want or simply can't recover from an error.

查看更多
人间绝色
6楼-- · 2018-12-31 04:12

Exception classes are like "normal" classes. You create a new class when it "is" a different type of object, with different fields and different operations.

As a rule of thumb, you should try balance between the number of exceptions and the granularity of the exceptions. If your method throws more than 4-5 different exceptions, you can probably merge some of them into more "general" exceptions, (e.g. in your case "AuthenticationFailedException"), and using the exception message to detail what went wrong. Unless your code handles each of them differently, you needn't creates many exception classes. And if it does, may you should just return an enum with the error that occured. It's a bit cleaner this way.

查看更多
步步皆殇っ
7楼-- · 2018-12-31 04:12

If it's code running inside a loop that will likely cause an exception over and over again, then throwing exceptions is not a good thing, because they are pretty slow for large N. But there is nothing wrong with throwing custom exceptions if the performance is not an issue. Just make sure that you have a base exception that they all inherite, called BaseException or something like that. BaseException inherits System.Exception, but all of your exceptions inherit BaseException. You can even have a tree of Exception types to group similar types, but this may or may not be overkill.

So, the short answer is that if it doesn't cause a significant performance penalty (which it should not unless you are throwing a lot of exceptions), then go ahead.

查看更多
登录 后发表回答