I have always been of the belief that if a method can throw an exception then it is reckless not to protect this call with a meaningful try block.
I just posted 'You should ALWAYS wrap calls that can throw in try, catch blocks.' to this question and was told that it was 'remarkably bad advice' - I'd like to understand why.
A method should only catch an exception when it can handle it in some sensible way.
Otherwise, pass it on up, in the hope that a method higher up the call stack can make sense of it.
As others have noted, it is good practice to have an unhandled exception handler (with logging) at the highest level of the call stack to ensure that any fatal errors are logged.
As Mitch and others stated, you shouldn't catch an exception that you do not plan on handling in some way. You should consider how the application is going to systematically handle exceptions when you are designing it. This usually leads to having layers of error handling based on the abstractions - for example, you handle all SQL-related errors in your data access code so that the part of the application that is interacting with domain objects is not exposed to the fact that there is a DB under the hood somewhere.
There are a few related code smells that you definitely want to avoid in addition to the "catch everything everywhere" smell.
"catch, log, rethrow": if you want scoped based logging, then write a class that emits a log statement in its destructor when the stack is unrolling due to an exception (ala std::uncaught_exception()). All that you need to do is declare a logging instance in the scope that you are interested in and, voila, you have logging and no unnecessary try/catch logic.
"catch, throw translated": this usually points to an abstraction problem. Unless you are implementing a federated solution where you are translating several specific exceptions into one more generic one, you probably have an unnecessary layer of abstraction... and don't say that "I might need it tomorrow".
"catch, cleanup, rethrow": this is one of my pet-peeves. If you see a lot of this, then you should apply Resource Acquisition is Initialization techniques and place the cleanup portion in the destructor of a janitor object instance.
I consider code that is littered with try/catch blocks to be a good target for code review and refactoring. It indicates that either exception handling is not well understood or the code has become an amœba and is in serious need of refactoring.
Because the next question is "I've caught an exception, what do I do next?" What will you do? If you do nothing - that's error hiding and the program could "just not work" without any chance to find what happened. You need to understand what exactly you will do once you've caught the exception and only catch if you know.
You don't need to cover every block with try-catches because a try-catch can still catch unhandled exceptions thrown in functions further down the call stack. So rather than have every function have a try-catch, you can have one at the top level logic of your application. For example, there might be a SaveDocument() top-level routine, which calls many methods which call other methods etc. These sub-methods don't need their own try-catches, because if they throw, it's still caught by SaveDocument()'s catch.
This is nice for three reasons: it's handy because you have one single place to report an error: the SaveDocument() catch block(s). There's no need to repeat this throughout all the sub-methods, and it's what you want anyway: one single place to give the user a useful diagnostic about something that went wrong.
Two, the save is cancelled whenever an exception is thrown. With every sub-method try-catching, if an exception is thrown, you get in to that method's catch block, execution leaves the function, and it carries on through SaveDocument(). If something's already gone wrong you likely want to stop right there.
Three, all your sub-methods can assume every call succeeds. If a call failed, execution will jump to the catch block and the subsequent code is never executed. This can make your code much cleaner. For example, here's with error codes:
int ret = SaveFirstSection();
if (ret == FAILED)
{
/* some diagnostic */
return;
}
ret = SaveSecondSection();
if (ret == FAILED)
{
/* some diagnostic */
return;
}
ret = SaveThirdSection();
if (ret == FAILED)
{
/* some diagnostic */
return;
}
Here's how that might be written with exceptions:
// these throw if failed, caught in SaveDocument's catch
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();
Now it's much clearer what is happening.
Note exception safe code can be trickier to write in other ways: you don't want to leak any memory if an exception is thrown. Make sure you know about RAII, STL containers, smart pointers, and other objects which free their resources in destructors, since objects are always destructed before exceptions.
Herb Sutter wrote about this problem here. For sure worth reading.
A teaser:
"Writing exception-safe code is fundamentally about writing 'try' and 'catch' in the correct places." Discuss.
Put bluntly, that statement reflects a fundamental misunderstanding of exception safety. Exceptions are just another form of error reporting, and we certainly know that writing error-safe code is not just about where to check return codes and handle error conditions.
Actually, it turns out that exception safety is rarely about writing 'try' and 'catch' -- and the more rarely the better. Also, never forget that exception safety affects a piece of code's design; it is never just an afterthought that can be retrofitted with a few extra catch statements as if for seasoning.
As stated in other answers, you should only catch an exception if you can do some sort of sensible error handling for it.
For example, in the question that spawned your question, the questioner asks whether it is safe to ignore exceptions for a lexical_cast from an integer to a string. Such a cast should never fail. If it did fail, something has gone terribly wrong in the program. What could you possibly do to recover in that situation? It's probably best to just let the program die, as it is in a state that can't be trusted. So not handling the exception may be the safest thing to do.
If you always handle exceptions immediately in the caller of a method that can throw an exception, then exceptions become useless, and you'd better use error codes.
The whole point of exceptions is that they need not be handled in every method in the call chain.
The best advice I've heard is that you should only ever catch exceptions at points where you can sensibly do something about the exceptional condition, and that "catch, log and release" is not a good strategy (if occasionally unavoidable in libraries).
I was given the "opportunity" to salvage several projects and executives replaced the entire dev team because the app had too many errors and the users were tired of the problems and run-around. These code bases all had centralized error handling at the app level like the top voted answer describes. If that answer is the best practice why didn't it work and allow the previous dev team to resolve issues? Perhaps sometimes it doesn't work? The answers above don't mention how long devs spend fixing single issues. If time to resolve issues is the key metric, instrumenting code with try..catch blocks is a better practice.
How did my team fix the problems without significantly changing the UI? Simple, every method was instrumented with try..catch blocked and everything was logged at the point of failure with the method name, method parameters values concatenated into a string passed in along with the error message, the error message, app name, date, and version. With this information developers can run analytics on the errors to identify the exception that occurs the most! Or the namespace with the highest number of errors. It can also validate that an error that occurs in a module is properly handled and not caused by multiple reasons.
Another pro benefit of this is developers can set one break-point in the error logging method and with one break-point and a single click of the "step out" debug button, they are in the method that failed with full access to the actual objects at the point of failure, conveniently available in the immediate window. It makes it very easy to debug and allows dragging execution back to the start of the method to duplicate the problem to find the exact line. Does centralized exception handling allow a developer to replicate an exception in 30 seconds? No.
The statement "A method should only catch an exception when it can handle it in some sensible way." This implies that developers can predict or will encounter every error that can happen prior to release. If this were true a top level, app exception handler wouldn't be needed and there would be no market for Elastic Search and logstash.
This approach also lets devs find and fix intermittent issues in production! Would you like to debug without a debugger in production? Or would you rather take calls and get emails from upset users? This allows you to fix issues before anyone else knows and without having to email, IM, or Slack with support as everything needed to fix the issue is right there. 95% of issues never need to be reproduced.
To work properly it needs to be combined with centralized logging that can capture the namespace/module, class name, method, inputs, and error message and store in a database so it can be aggregated to highlight which method fails the most so it can be fixed first.
Sometimes developers choose to throw exceptions up the stack from a catch block but this approach is 100 times slower than normal code that doesn't throw. Catch and release with logging is preferred.
This technique was used to quickly stabilize an app that failed every hour for most users in a Fortune 500 company developed by 12 Devs over 2 years. Using this 3000 different exceptions were identified, fixed, tested, and deployed in 4 months. This averages out to a fix every 15 minutes on average for 4 months.
I agree that it is not fun to type in everything needed to instrument the code and I prefer to not look at the repetitive code, but adding 4 lines of code to each method is worth it in the long run.
I agree with the basic direction of your question to handle as many exceptions as possible at the lowest level.
Some of the existing answer go like "You don't need to handle the exception. Someone else will do it up the stack." To my experience that is a bad excuse to not think about exception handling at the currently developed piece of code, making the exception handling the problem of someone else or later.
That problem grows dramatically in distributed development, where you may need to call a method implemented by a co-worker. And then you have to inspect a nested chain of method calls to find out why he/she is throwing some exception at you, which could have been handled much easier at the deepest nested method.
The advice my computer science professor gave me once was: "Use Try and Catch blocks only when it's not possible to handle the error using standard means."
As an example, he told us that if a program ran into some serious issue in a place where it's not possible to do something like:
int f()
{
// Do stuff
if (condition == false)
return -1;
return 0;
}
int condition = f();
if (f != 0)
{
// handle error
}
Then you should be using try, catch blocks. While you can use exceptions to handle this, it's generally not recommended because exceptions are expensive performance wise.
If you want to test the outcome of every function, use return codes.
The purpose of Exceptions is so that you can test outcomes LESS often. The idea is to separate exceptional (unusual, rarer) conditions out of your more ordinary code. This keeps the ordinary code cleaner and simpler - but still able to handle those exceptional conditions.
In well-designed code deeper functions might throw and higher functions might catch. But the key is that many functions "in between" will be free from the burden of handling exceptional conditions at all. They only have to be "exception safe", which does not mean they must catch.
I would like to add to this discussion that, since C++11, it does make a lot of sense, as long as every catch block rethrows the exception up until the point it can/should be handled. This way a backtrace can be generated. I therefore believe the previous opinions are in part outdated.
Use std::nested_exception and std::throw_with_nested
It is described on StackOverflow here and here how to achieve this.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
I feel compelled to add another answer although Mike Wheat's answer sums up the main points pretty well. I think of it like this. When you have methods that do multiple things you are multiplying the complexity, not adding it.
In other words, a method that is wrapped in a try catch has two possible outcomes. You have the non-exception outcome and the exception outcome. When you're dealing with a lot of methods this exponentially blows up beyond comprehension.
Exponentially because if each method branches in two different ways then every time you call another method you're squaring the previous number of potential outcomes. By the time you've called five methods you are up to 256 possible outcomes at a minimum. Compare this to not doing a try/catch in every single method and you only have one path to follow.
That's basically how I look at it. You might be tempted to argue that any type of branching does the same thing but try/catches are a special case because the state of the application basically becomes undefined.
So in short, try/catches make the code a lot harder to comprehend.
Besides the above advice, personally I use some try+catch+throw; for the following reason:
At boundary of different coder, I use try + catch + throw in the code written by myself, before the exception being thrown to the caller which is written by others, this gives me a chance to know some error condition occured in my code, and this place is much closer to the code which initially throw the exception, the closer, the easier to find the reason.
At the boundary of modules, although different module may be written my same person.
Learning + Debug purpose, in this case I use catch(...) in C++ and catch(Exception ex) in C#, for C++, the standard library does not throw too many exception, so this case is rare in C++. But common place in C#, C# has a huge library and an mature exception hierarchy, the C# library code throw tons of exception, in theory I(and you) should know every exceptions from the function you called, and know the reason/case why these exception being thrown, and know how to handle them(pass by or catch and handle it in-place)gracefully. Unfortunately in reality it's very hard to know everything about the potential exceptions before I write one line of code. So I catch all and let my code speak aloud by logging(in product environment)/assert dialog(in development environment) when any exception really occurs. By this way I add exception handling code progressively. I know it conflit with good advice but in reality it works for me and I don't know any better way for this problem.
You have no need to cover up every part of your code inside try-catch. The main use of the try-catch block is to error handling and got bugs/exceptions in your program. Some usage of try-catch -
You can use this block where you want to handle an exception or simply you can say that the block of written code may throw an exception.
If you want to dispose your objects immediately after their use, You can use try-catch block.
Related
At what point during development do you typically implement your exception handlers? Do you write them at the same time as you write the surrounding code, or do you write your code and then come back to "harden" it later?
I typically do the latter so that I can see exactly where and how my code fails, but I worry that my code isn't as resilient as it could be if I would have written the exception handlers right away.
At the same time, I don't want to spend a whole bunch of development time figuring out all the possible ways that my code could fail when there are other implementation details that I haven't settled on yet.
I'm curious as to how other developers do this.
Update: I just wanted to thank everyone for their answers!
I either write the exception handlers immediately, or I allow the exceptions to propagate upwards. I'm a big fan of what I call the "You're Not Going To Go Back And Fix It Later, Are You?" principle. You say you will, but honestly, once you get it working, you're not going to go back and fix it later, are you? Just get it right right now! Write your exception handlers right away, or add a throws clause and make it somebody else's problem. Do the right thing right now.
But you know what, sometimes you can't. Whatever you do, do not swallow exceptions with empty exception handlers! This is evil:
try {
connection.close();
}
catch (Exception e) {
// TODO Auto-generated code
}
I drop kick anybody on my team who checks that in.
If you really don't know what to do about an exception and cannot add a throws clause to propagate it upwards, at least do something halfway responsible. Print a stack trace, if nothing else. It's not ideal but at least you're not hiding errors.
catch (IOException exception) {
exception.printStackTrace();
}
Logging it via your application's logging system is better, though you shouldn't make a habit of it. It's supposed to be the caller's responsibility to handle these kinds of things.
catch (IOException exception) {
log.error(exception, "Unable to open configuration file %s.", fileName);
}
As a last resort, you can do an end run around your throws clause by wrapping your exception in a RuntimeException. At least you're giving somebody higher up the call chain a chance to handle the error, which is normally the Right Thing To Do.
catch (IOException exception) {
throw new RuntimeException(exception);
}
In my exception handler I usually raise a higher-level exception. For example, when parsing a file in Python, some string, list and dict operations may raise ValueError, IndexError or KeyError. These exceptions are usually not helpful for the caller, so I write an exception handler, which raises a descriptive MyParseError. I do this at the same time when writing the method, but later, when writing the test, I sometimes make the exception message more verbose.
If I am calling an API then I look at what exceptions can be thrown and decide based on the list. The exceptions that can be thrown generally fall into categories:
Improbable in my view this will get thrown - make sure that code fails nicely
Realistic that this will get thrown - what should I do if this gets called?
Certain that this will get thrown based on current inputs - add validation to inputs to stop it getting thrown
Could I raise a more relevant exception? - if an exception is likely to get to get called would it be clearer for other calling code if I raised a new/different exception
In general I think it is always good practice to have catch all try catch blocks high up in the call stack that can catch general exceptions (Throwable) and then report these nicely to the user - perhaps with an interface that will then email the error and stacktrace to the development team and ask for user comments.
Sometimes both. In some cases I know of the exceptions that can be thrown and I want to handle as I'm writing the code, and so I write the handlers right then and there. Other times I don't know of all of the exceptions and find them later, either through documentation, testing or both.
It's a combination of both. There are things that I know can go wrong like database connections, configuration settings, file read/writes as well as the red flags from the functional/tech specifications. I try to setup the try/catch for those ASAP.
As the application gets bigger over time I then start to see patterns and trends with either how the user is using the application and or how me and or the team has developed it and add those try/catches as needed.
It kind of depends on the nature of the project you are working on. In my case, if I'm familiar with the logic of the system, I should know where, and how, to handle exceptions even before writing code. On the other hand, I would write my stuff, test it and then write the handlers.
during development, when:
a unit test require it
when some presentation/persistence code require it
EDIT
in Java sometimes, you must take care error handling at very early stage (checked exceptions) and sometimes this is very annoying.
My approach is to address exception handling immediately, since it's not some aimless burden that you can happily postpone.
Just handle the exceptions that apply at the point that you write your code, propagate all those that do not matter, and only come back later to fix whatever is broken, saves you a lot of tears.
As a rule, not only do I write my exception handling when I'm writing the code, but I try to write the code to avoid exceptions in the first place. The advantages are that if I know I need to handle an exception I remember to and if I can avoid an exception that is always a plus. I also test my code after I've written it using boundary conditions to see if there's any possible exceptions that I may have missed.
Writing the handlers when you are writing the actual code is the best habbit i guess because you are very clear of the failures that may occur although you can add others when you discover it.
handling the exception may be tedious for the first time but it would save lot of time while debugging for some error i.e support.
I have been programming for the last 3 years. When I program, I use to handle all known exceptions and alert the user gracefully. I have seen some code recently which has almost all methods wrapped inside try/catch blocks. The author says it is part of defensive programming. I wonder, is this really defensive programming? Do you recommend putting all your code in try blocks?
My basic rule is : Unless you can fix the problem which caused the exception, do not catch it, let it bubble up to a level where it can be dealt with.
In my experience, 95% of all catch blocks either just ignore the exception (catch {}) or merely log the error and rethrow the exception. The latter might seem like the right thing to do, but in practice, when this is done at every level, you merely end up with your log cluttered with five copies of the same error message. Usually these apps have an "ignore catch" at the top most level (since "we have try/catch at all the lower levels"), resulting in a very slow app with lots of missed exceptions, and an error log that too long for anyone to be willing to look through it.
Extensive use of Try...Catch isn't defensive programming, it's just nailing the corpse in an upright position.
Try...Finally can be used extensively for recovery in the face of unexpected exceptions. Only if you expect an exception and now how to deal with it should you use Try..Catch instead.
Sometimes I see Try..Catch System.Exception, where the catch block just logs the exception and re-throws. There are at least 3 problems with that approach:
Rethrow assumes an unhandled exception, and therefore that the program should terminate because it's in an unknown state. But catch causes the Finally blocks below the Catch block to run. In an undefined situation, the code in these Finally blocks could make the problem worse.
The code in those Finally blocks will change program state. So any logging won't capture the actual program state when the exception was originally thrown. And investigation will be more difficult because the state has changed.
It gives you a miserable debugging experience, because the debugger stops on the rethrow, not the original throw.
No, it's not "defensive programming." Your coworker is trying to rationalize his bad habit by employing a buzzword for a good habit.
What he's doing should be called "sweeping it under the rug." It's like uniformly (void)-ing the error-status return value from method calls.
The term "defensive programming" stands for writing code in such a way that it can recover from error situations or that it avoid the error situation altogether. For example:
private String name;
public void setName(String name) {
}
How do you handle name == null? Do you throw an exception or do you accept it? If it doesn't make sense to have an object without a name, then you should throw an exception. What about name == ""?
But ... later you write an editor. While you set up the UI, you find that there are situations where a user can decide to take the name away or the name can become empty while the user edits it.
Another example:
public boolean isXXX (String s) {
}
Here, the defensive strategy is often to return false when s == null (avoid NPEs when you can).
Or:
public String getName() {
}
A defensive programmer might return "" if name == null to avoid NPEs in calling code.
If you're going to handle random exceptions, handle them in only one place - the very top of the application, for the purposes of:
presenting a friendly message to the user, and
saving the diagnostics.
For everything else, you want the most immediate, location-specific crash possible, so that you catch these things as early as possible - otherwise exception handling becomes a way of hiding sloppy design and code.
In most cases where the exception is predictable, it's possible to test ahead of time, for the condition that the exception handler will catch.
In general, If...Else is much better than Try...Catch.
Catching random exceptions is bad. What then?
Ignore them? Excellent. Let me know how that works for them.
Log them and keep running? I think not.
Throw a different exception as part of crashing? Good luck debugging that.
Catching exceptions for which you can actually do something meaningful is good. These cases are easy to identify and maintain.
Can I just say as an aside here that every time one of my co-workers writes a method signature with "throws Exception" instead of listing the types of exceptions the method really throws, I want to go over and shoot them in the head? The problem is that after a while you've got 14 levels of calls all of which say "throws Exception", so refactoring to make them declare what they really throw is a major exercise.
There is such a thing as "too much" processing, and catching all exceptions kindof defeats the point. Specifically for C++, the catch(...) statement does catch all exceptions but you can't process the contents of that exception because you don't know the type of the exception (and it could be anything).
You should catch the exceptions you can handle fully or partially, rethrowing the partial exceptions. You should not catch any exceptions that you can't handle, because that will just obfuscate errors that may (or rather, will) bite you later on.
I would recommend against this practice. Putting code into try-catch blocks when you know the types of exceptions that can be thrown is one thing. It allows you, as you stated, to gracefully recover and/or alert the user as to the error. However, putting all your code inside such blocks where you don't know what the error is that may occur is using exceptions to control program flow, which is a big no-no.
If you are writing well-structured code, you will know about every exception that can occur, and can catch those specifically. If you don't know how a particular exception can be thrown, then don't catch it, just-in-case. When it happens, you can then figure out the exception, what caused it, and then catch it.
I guess the real answer is "It depends". If try-catch blocks are catching very generic exceptions then I would say it is defensive programming in the same way that never driving out of your neighborhood is defensive driving. A try-catch (imo) should be tailored to specific exceptions.
Again, this is just my opinion, but my concept of defensive programming is that you need fewer/smaller try-catch blocks not more/larger ones. Your code should be doing everything it can to make sure an exception condition can never exist in the first place.
In C++ the one reason to write lots of try/catch blocks is to get a stack trace of where the exception was thrown. What you do is write a try/catch everywhere, and (assuming you aren't at the right spot to deal with the exception) have the catch log some trace info then re-throw the exception. In this way, if an exception bubbles all the way up and causes the program to terminate, you'll have a full stack trace of where it all started to go wrong (if you don't do this, then an unhandled C++ exception will have helpfully unwound the stack and eradicated any possibility of you figuring out where it came from).
I would imagine that in any language with better exception handling (i.e. uncaught exceptions tell you where they came from) you'd want to only catch exceptions if you could do something about them. Otherwise, you're just making your program hard to read.
I've found "try" "catch" blocks to be very useful, especially if anything realtime (such as accessing a database) is used.
Too many? Eye of the beholder.
I've found that copying a log to Word, and searching with "find" -- if the log reader does not have "find" or "search" as part of its included tools -- is a simple but excellent way to slog through verbose logs.
It certainly seems "defensive" in the ordinary sense of the word.
I've found, through experience, to follow whatever your manager, team-leader, or co-worker does. If you're just programming for yourself, use them until the code is "stable" or in debug builds, and then remove them when done.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
It's my understanding that common wisdom says to only use exceptions for truly exceptional conditions (In fact, I've seen that statement here at SO several times).
However, Krzysztof Cwalina says:
One of the biggest misconceptions about exceptions is that they are for “exceptional conditions.” The reality is that they are for communicating error conditions. From a framework design perspective, there is no such thing as an “exceptional condition”. Whether a condition is exceptional or not depends on the context of usage, --- but reusable libraries rarely know how they will be used. For example, OutOfMemoryException might be exceptional for a simple data entry application; it’s not so exceptional for applications doing their own memory management (e.g. SQL server). In other words, one man’s exceptional condition is another man’s chronic condition.
He then also goes on to say that exceptions should be used for:
Usage errors
Program errors
System failures
Considering Krzysztof Cwalina is the PM for the CLR team at MS I ask: What do you think of his statement?
This sounds over-simplistic, but I think it makes sense to simply use exceptions where they are appropriate. In languages like Java and Python, exceptions are very common, especially in certain situations. Exceptions are appropriate for the type of error you want to bubble up through a code path and force the developer to explicitly catch. In my own coding, I consider the right time to add an exception when the error either can't be ignored, or it's simply more elegant to throw an exception instead of returning an error value to a function call etc.
Some of the most appropriate places for exceptions that I can think of offhand:
NotImplementedException - very appropriate way of designating that a particular
method or function isn't available, rather than simply returning without doing
anything.
OutOfMemory exceptions - it's difficult to imagine a better way of handling this
type of error, since it represents a process-wide or OS-wide memory allocation
failure. This is essential to deal with, of course!
NullPointerException - Accessing a null variable is a programmer mistake, and IMO
this is another good place to force an error to bubble to the surface
ArrayIndexException - In an unforgiving language like C, buffer overflows
are disastrous. Nicer languages might return a null value of some type, or in
some implementations, even wrap around the array. In my opinion, throwing an
exception is a much more elegant response.
This is by no means a comprehensive list, but hopefully it illustrates the point. Use exceptions where they are elegant and logical. As always with programming, the right tool for the right job is good advice. There's no point going exception-crazy for nothing, but it's equally unwise to completely ignore a powerful and elegant tool at your disposal.
For people who write frameworks, perhaps it's interesting.
For the rest of us, it's confusing (and possibly useless.) For ordinary applications, exceptions have to be set aside as "exceptional" situations. Exceptions interrupt the ordinary sequential presentation of your program.
You should be circumspect about breaking the ordinary top-to-bottom sequential processing of your program. The exception handling is -- intentionally -- hard to read. Therefore, reserve exceptions for things that are outside the standard scenarios.
Example: Don't use exceptions to validate user input. People make input mistakes all the time. That's not exceptional, that's why we write software. That's what if-statements are for.
When your application gets an OutOfMemory exception, there's no point in catching it. That's exceptional. The "sequential execution" assumption is out the window. Your application is doomed, just crash and hope that your RDBMS transaction finishes before you crash.
It is indeed difficult to know what exactly construes an "exceptional condition" which warrants the use of an exception in a program.
One instance that is very helpful for using communicating the cause of errors. As the quote from Krzysztof Cwalina mentions:
One of the biggest misconceptions
about exceptions is that they are for
“exceptional conditions.” The reality
is that they are for communicating
error conditions.
To give a concrete example, say we have a getHeader(File f) method that is reading some header from a file and returns a FileHeader object.
There can be several problems which can arise from trying to read data from a disk. Perhaps the file specified doesn't exist, file contains data that can't be read, unexpected disk access errors, running out of memory, etc. Having multiple means of failure means that there should be multiple ways to report what went wrong.
If exceptions weren't used, but there was a need to communicate the kind of error that occurred, with the current method signature, the best we can do is to return a null. Since getting a null isn't very informative, the best communication we get from that result is that "some kind of error happened, so we couldn't continue, sorry." -- It doesn't communicate the cause of the error.
(Or alternatively, we may have class constants for FileHeader objects which indicate FileNotFound conditions and such, emulating error codes, but that really reeks of having a boolean type with TRUE, FALSE, FILE_NOT_FOUND.)
If we had gotten a FileNotFound or DeviceNotReady exception (hypothetical), at least we know what the source of the error was, and if this was an end user application, we could handle the error in ways to solve the problem.
Using the exception mechanism gives a means of communication that doesn't require a fallback to using error codes for notification of conditions that aren't within the normal flow of execution.
However, that doesn't mean that everything should be handled by exceptions. As pointed out by S.Lott:
Don't use exceptions to validate user
input, for example. People make
mistakes all the time. That's what
if-statements are for.
That's one thing that can't be stressed enough. One of the dangers of not knowing when exactly to use exceptions is the tendency to go exception-happy; using exceptions where input validation would suffice.
There's really no point in defining and throwing a InvalidUserInput exception when all that is required to deal in such a situation is to notify the user of what is expected as input.
Also, it should be noted that user input is expected to have faulty input at some point. It's a defensive measure to validate input before handing off input from the outside world to the internals of the program.
It's a little bit difficult to decide what is exceptional and what is not.
Since I usually program in Python, and in that language exceptions are everywhere, to me an exception may represent anything from a system error to a completely legitimate condition.
For example, the "pythonic" way to check if a string contains an integer is to try int(theString) and see if it raises an exception. Is that an "exceptional error"?
Again, in Python the for loop is always thought of as acting on an iterator, and an iterator must raise a 'StopIteration' exception when it finishes its job (the for loop catches that exception). Is that "exceptional" by any means?
I think the closer to the ground are you are the less appropriate exceptions as a means of error communication become. At a higher abstraction such as in Java or .net, an exception may make for an elegant way to pass error messages to your callers. This however is not the case in C. This is also a framework vs api design decision.
If you practice "tell, don't ask" then an exception is just the way a program says "I can't do that". It is "exceptional" in that you say "do X" and it cannot do X. A simple error-handling situation. In some languages it is quite common to work this way, in Java and C++ people have other opinions because exceptions become quite costly.
General: exception just means "I can't"
Pragmatic: ... if you can afford to work that way in your language.
Citizenship: ... and your team allows it.
Here is the definition for exception: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.
Therefore, to answer your question, no. Exceptions are for disruptive events, which may or may not be exceptional. I love this definition, it's simple and works every time - if you buy into exceptions like I do. E.g., a user submits an incorrect un/pw, or you have an illegal argument/bad user input. Throwing an exception here is the most straightforward way of solving these problems, which are disruptive, but not exceptional, nor even unanticipated.
They probably should have been called disruptions, but that boat has sailed.
I think there are a couple of good reasons why exceptions should be used to catch unexpected problems.
Firstly, they create an object to encapsulate the exception, which by definition must make it a lot more expensive than processing a simple if-statement. As a Java example, you should call File.exists() rather than routinely expecting and handling a FileNotFoundException.
Secondly, exceptions that are caught outside the current method (or maybe even class) make the code much harder to read than if the handling is all there in in the one method.
Having said that, I personally love exceptions. They relieve you of the need of explicitly handling all of those may-happen-but-probably-never-will type errors, which cause you to repetitively write print-an-error-and-abort-on-non-zero-return-code handling of every method call.
My bottom line is... if you can reasonably expect it to happen then it's part of your application and you should code for it. Anything else is an exception.
I've been wondering about this myself. What do we mean by "exceptional"? Maybe there's no strict definition, but are there any rules of thumb that we can use to decide what's exceptional, in a given context?
For example, would it be fair to say that an "exceptional" condition is one that violates the contract of a function?
KCwalina has a point.
It will be good to identify cases where the code will fail (upto a limit)
I agree with S.Lott that sometimes validating is better than to throw Exception.
Having said that, OutOfMemory is not what you might expect in your application (unless it is allocating a large memory & needs memory to go ahead).
I think, it depends on the domain of the application.
The statement from Krzysztof Cwalina is a little misleading. The original statement refers 'exceptional conditions', for me it is natural that I am the one who defines what's exceptional or not. Nevertheless, I think the message passed through OK, since I think we are all talking about 'developer' exceptions.
Exceptions are great for communication, but with a little hierarchy design they are also great for some separation of concerns, specially between layers (DAO, Business, etc). Of course, this is only useful if you treat these exceptions differently.
A nice example of hierarchy is spring's data access exception hierarchy.
I think he is right. Take a look at number parsing in java. You cant even check input string before parsing. You are forced to parse and retrieve NFE if something went wrong. Is parse failure something exceptional? I think no.
I certainly believe exceptions should be used only if you have an exceptional condition.
The trouble is in the definition of "exceptional". Here is mine:
A condition is exceptional if it is outside the assumed normal
behaviour of the part of the system that raises the exception.
This has some implications:
Exceptional depends on your assumptions. If a function assumes that it is passed valid parameters, then throwing an IllegalArgumentException is OK. However if a function's contract says that it will correct input errors in input in some way, then this usage is "normal" and it shouldn't throw an exception on an input error.
Exceptional depends on sub-system layering. A network IO function could certainly raise an exception if the network is discommented, as it assumes a valid connection. A ESB-based message broker however would be expected to handle dropped connections, so if it used such a network IO function internally then it would need to catch and handle the error appropriately. In case it isn't obvious, try/catch is effectively equivalent to a subsystem saying "a condition which is exceptional for one of my components is actually considered normal by me, so I need to handle it".
The saying that exceptions should be used for exceptional circumstances is used in "Effective Java Second Edition": one of the best java books.
The trouble is that this is taken out of context. When the author states that exceptions should be exceptional, he had just shown an example of using exceptions to terminate a while loop - a bad exception use. To quote:
exceptions are, as their name implies, to
be used only for exceptional conditions; they should never be used for ordinary
control flow.
So it all depends on your definition of "exception condition". Taken out of context you can imply that it should very rarely be used.
Using exceptions in place of returning error codes is good, while using them in order to implement a "clever" or "faster" technique is not good. That's usually what is meant by "exceptional condition".
Checked exception - minor errors that aren't bugs and shouldn't halt execution. ex. IO or file parsing
Unchecked exception - programming "bug" that disobeys a method contract - ex. OutOfBoundsException. OR a error that makes continuing of execution a very bad idea - ex IO or file parsing of a very important file. Perhaps a config file.
What it comes down to is what tool is needed to do the job.
Exceptions are a very powerful tool. Before using them ask if you need this power and the complexity that comes with it.
Exceptions may appear simple, because you know that when the line with the exception is hit everything comes to a halt. What happens from here though?
Will an uncaught exception occur?
Will the exception be caught by global error handling?
Will the exception be handled by more nested and detailed error handling?
You have to know everything up the stack to know what that exception will do. This violates the concept of independence. That method now is dependent on error handling to do what you expect it to.
If I have a method I shouldn't care what is outside of that method. I should only care what the input is, how to process it, and how to return the response.
When you use an exception you are essentially saying, I don't care what happens from here, something went wrong and I don't want it getting any worse, do whatever needs to be done to mitigate the issue.
Now if you care about how to handle the error, you will do some more thinking and build that into the interface of the method e.g. if you are attempting to find some object possibly return the default of that object if one can't be found rather than throwing some exception like "Object not found".
When you build error handling into your methods interface, not only is that method's signature more descriptive of what it can do, but it places the responsibility of how to handle the error on the caller of the method. The caller method may be able to work through it or not, and it would report again up the chain if not. Eventually you will reach the application's entry point. Now it would be appropriate to throw an exception, since you better have a good understanding of how exceptions will be handled if you're working with the applications public interface.
Let me give you an example of my error handling for a web service.
Level 1. Global error handling in global.asax - That's the safety net to prevent uncaught exceptions. This should never intentionally be reached.
Level 2. Web service method - Wrapped in a try/catch to guarantee it will always comply with its json interface.
Level 3. Worker methods - These get data, process it, and return it raw to the web service method.
In the worker methods it's not right to throw an exception. Yes I have nested web service method error handling, but that method can be used in other places where this may not exist.
Instead if a worker method is used to get a record and the record can't be found, it just returns null. The web service method checks the response and when it finds null it knows it can't continue. The web service method knows it has error handling to return json so throwing an exception will just return the details in json of what happened. From a client's perspective it's great that it got packaged into json that can be easily parsed.
You see each piece just knows what it needs to do and does it. When you throw an exception in the mix you hijack the applications flow. Not only does this lead to hard to follow code, but the response to abusing exceptions is the try/catch. Now you are more likely to abuse another very powerful tool.
All too often I see a try/catch catching everything in the middle of an a application, because the developer got scared a method they use is more complex than it appears.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
Yesterday I was having a heated debate with a coworker on what would be the preferred error reporting method. Mainly we were discussing the usage of exceptions or error codes for reporting errors between application layers or modules.
What rules do you use to decide if you throw exceptions or return error codes for error reporting?
In high-level stuff, exceptions; in low-level stuff, error codes.
The default behaviour of an exception is to unwind the stack and stop the program, if I'm writing a script an and I go for a key that's not in a dictionary it's probably an error, and I want the program to halt and let me know all about that.
If, however, I'm writing a piece of code which I must know the behaviour of in every possible situation, then I want error codes. Otherwise I have to know every exception that can be thrown by every line in my function to know what it will do (Read The Exception That Grounded an Airline to get an idea of how tricky this is). It's tedious and hard to write code that reacts appropriately to every situation (including the unhappy ones), but that's because writing error-free code is tedious and hard, not because you're passing error codes.
Both Raymond Chen and Joel have made some eloquent arguments against using exceptions for everything.
I normally prefer exceptions, because they have more contextual information and can convey (when properly used) the error to the programmer in a clearer fashion.
On the other hand, error codes are more lightweight than exceptions but are harder to maintain. Error checking can inadvertently be omitted. Error codes are harder to maintain because you have to keep a catalog with all error codes and then switch on the result to see what error was thrown. Error ranges can be of help here, because if the only thing we are interested in is if we are in the presence of an error or not, it is simpler to check (e.g., an HRESULT error code greater or equal to 0 is success and less than zero is failure). They can inadvertently be omitted because there is no programmatic forcing that the developer will check for error codes. On the other hand, you cannot ignore exceptions.
To summarize I prefer exceptions over error codes in almost all situations.
I prefer exceptions because
they interupt the flow of logic
they benefit from class hierarchy which gives more features/functionality
when used properly can represent a wide range of errors (e.g. an InvalidMethodCallException is also a LogicException, as both occur when there's a bug in your code that should be detectable before runtime), and
they can be used to enhance the error (i.e. a FileReadException class definition can then contain code to check whether the file exists, or is locked, etc)
Error codes can be ignored (and often are!) by the callers of your functions. Exceptions at least force them to deal with the error in some way. Even if their version of dealing with it is to have an empty catch handler (sigh).
Exceptions over error codes, no doubt about it. You get much of the same benefits from exceptions as you do with error codes, but also much more, without the shortcomings of error codes. The only knock on exceptions is that it is slightly more overhead; but in this day and age, that overhead should be considered negligible for nearly all applications.
Here are some articles discussing, comparing and contrasting the two techniques:
Object Oriented Exception Handling in Perl
Exceptions vs. status returns
There are some good links in those that can give you further reading.
I would never mix the two models...it's too hard to convert from one to the other as you move from one part of the stack which is using error codes, to a higher piece that is using exceptions.
Exceptions are for "anything that stops or inhibits the method or subroutine from doing what you asked it to do" ... NOT to pass messages back about irregularities or unusual circumstances, or the state of the system, etc. Use return values or ref (or out) parameters for that.
Exceptions allow methods to be written (and utilized) with semantics that are dependent on the method's function, i.e. a method that returns an Employee object or List of Employees can be typed to do just that, and you can utilize it by calling.
Employee EmpOfMonth = GetEmployeeOfTheMonth();
With error codes, all methods return an error code, so, for those that need to return something else to be used by the calling code, you have to pass a reference variable to be populated with that data, and test the return value for the error code, and handle it, on every function or method call.
Employee EmpOfMonth;
if (getEmployeeOfTheMonth(ref EmpOfMonth) == ERROR)
// code to Handle the error here
If you code so that each method does one and only one simple thing, then you should throw an exception whenever the method cannot accomplish the method's desired objective. Exceptions are much richer and easier to use in this way than error codes. Your code is much cleaner - The standard flow of the "normal" code path can be devoted strictly to the case where the method IS able to accomplish what you wanted it to do... And then the code to clean up, or handle the "exceptional" circumstances when something bad happens that prevents the method from completing successfully can be siloed away from the normal code. Additionally, if you can't handle the exception where it occurred, and must pass it up the stack to a UI, (or worse, across the wire from a mid-tier component to a UI), then with the exception model, you don't need to code every intervening method in your stack to recognize and pass the exception up the stack... The exception model does this for you automagically.... With error codes, this piece of the puzzle can get onerous very rapidly.
You should use both. The thing is to decide when to use each one.
There are a few scenarios where exceptions are the obvious choice:
In some situations you can't do anything with the error code, and you just need to handle it in an upper level in the call stack, usually just log the error, display something to the user or close the program. In these cases, error codes would require you to bubble up the error codes manually level by level which is obviously much easier to do with exceptions. The point is that this is for unexpected and unhandleable situations.
Yet about situation 1 (where something unexpected and unhandleable happens you just wan't to log it), exceptions can be helpful because you might add contextual information. For example if I get a SqlException in my lower-level data helpers, I will want to catch that error in the low-level (where I know the SQL command that caused the error) so I can capture that information and rethrow with additional information. Please note the magic word here: rethrow, and not swallow.
The first rule of exception handling: do not swallow exceptions. Also, note that my inner catch doesn't need to log anything because the outer catch will have the whole stack trace and may log it.
In some situations you have a sequence of commands, and if any of them fail you should cleanup/dispose resources(*), whether or not this is an unrecoverable situation (which should be thrown) or a recoverable situation (in which case you can handle locally or in the caller code but you don't need exceptions). Obviously it's much easier to put all those commands in a single try, instead of testing error codes after each method, and cleanup/dispose in the finally block. Please note that if you want the error to bubble up (which is probably what you want), you don't even need to catch it - you just use the finally for cleanup/dispose - you should only use catch/retrow if you want to add contextual information (see bullet 2).
One example would be a sequence of SQL statements inside a transaction block. Again, this also a "unhandleable" situation, even if you decide to catch it early (treat it locally instead of bubbling up to the top) it's still a fatal situation from where the best outcome is to abort everything or at least abort a large part of the process.
(*) This is like the on error goto that we used in old Visual Basic
In constructors you can only throw exceptions.
Having said that, in all other situations where you're returning some information on which the caller CAN/SHOULD take some action, using return codes is probably a better alternative. This includes all expected "errors", because probably they should be handled by the immediate caller, and will hardly need to be bubbled up too many levels up in the stack.
Of course it's always possible to treat expected errors as exceptions, and catch then immediately one level above, and it's also possible to encompass every line of code in a try catch and take actions for each possible error. IMO, this is bad design, not only because it's much more verbose, but specially because the possible exceptions that might be thrown are not obvious without reading the source code - and exceptions could be thrown from any deep method, creating invisible gotos. They break code structure by creating multiple invisible exit points that make code hard to read and inspect. In other words, you should never use exceptions as flow-control, because that would be hard for others to understand and maintain. It can get even difficult to understand all possible code flows for testing.
Again: for correct cleanup/dispose you can use try-finally without catching anything.
The most popular criticism about return codes is that "someone could ignore the error codes, but in the same sense someone can also swallow exceptions. Bad exception handling is easy in both methods. But writing good error-code-based program is still much easier than writing an exception-based program. And if one by any reason decides to ignore all errors (the old on error resume next), you can easily do that with return codes and you can't do that without a lot of try-catchs boilerplate.
The second most popular criticism about return codes is that "it's difficult to bubble up" - but that's because people don't understand that exceptions are for non-recoverable situations, while error-codes are not.
Deciding between exceptions and error codes is a gray area. It's even possible that you need to get an error code from some reusable business method, and then you decide to wrap that into an exception (possibly adding information) and let it bubble up. But it's a design mistake to assume that ALL errors should be thrown as exceptions.
To sum it up:
I like to use exceptions when I have an unexpected situation, in which there's not much to do, and usually we want to abort a large block of code or even the whole operation or program. This is like the old "on error goto".
I like to use return codes when I have expected situations in which the caller code can/should take some action. This includes most business methods, APIs, validations, and so on.
This difference between exceptions and error codes is one of the design principles of the GO language, which uses "panic" for fatal unexpected situations, while regular expected situations are returned as errors.
Yet about GO, it also allows multiple return values , which is something that helps a lot on using return codes, since you can simultaneously return an error and something else. On C#/Java we can achieve that with out parameters, Tuples, or (my favorite) Generics, which combined with enums can provide clear error codes to the caller:
public MethodResult<CreateOrderResultCodeEnum, Order> CreateOrder(CreateOrderOptions options)
{
....
return MethodResult<CreateOrderResultCodeEnum>.CreateError(CreateOrderResultCodeEnum.NO_DELIVERY_AVAILABLE, "There is no delivery service in your area");
...
return MethodResult<CreateOrderResultCodeEnum>.CreateSuccess(CreateOrderResultCodeEnum.SUCCESS, order);
}
var result = CreateOrder(options);
if (result.ResultCode == CreateOrderResultCodeEnum.OUT_OF_STOCK)
// do something
else if (result.ResultCode == CreateOrderResultCodeEnum.SUCCESS)
order = result.Entity; // etc...
If I add a new possible return in my method, I can even check all callers if they are covering that new value in a switch statement for example. You really can't do that with exceptions. When you use return codes, you'll usually know in advance all possible errors, and test for them. With exceptions you usually don't know what might happen. Wrapping enums inside exceptions (instead of Generics) is an alternative (as long as it's clear the type of exceptions that each method will throw), but IMO it's still bad design.
EDIT 2020-10-11:
Since C# 7.0 (March 2017) instead of Generics I prefer to use the new Tuples syntax which allows multiple return values (so we can use GO-like syntax where methods return a result OR an error).
public enum CreateUserResultCodeEnum
{
[Description("Username not available")]
NOT_AVAILABLE,
}
public (User user, CreateUserResultCodeEnum? error) CreateUser(string userName)
// (try to create user, check if not available...)
if (notAvailable)
return (null, CreateUserResultCodeEnum.NOT_AVAILABLE);
return (user, null);
}
// How to call and deconstruct tuple:
(var user, var error) = CreateUser("john.doe");
if (user != null) ...
if (error == CreateUserResultCodeEnum.NOT_AVAILABLE) ...
// Or returning a single object (named tuple):
var result = CreateUser("john.doe");
if (result.user != null) ...
if (result.error == CreateUserResultCodeEnum.NOT_AVAILABLE) ...
EDIT 2021-01-09:
A few days ago I wrote this blog post about how we can (in some cases!) use multiple returns instead of exceptions (like golang convention explained above, not supposed to replace all your exceptions but supposed to give you arsenal to decide between when to use exceptions and when to use return codes).
By the end of the post I'm mixing two models - basically I'm using the ValueTuple syntax (which is very concise and elegant) but yet using Generics as the underlying structure.
Basically I use implicit conversion operator and type deconstructors to convert back and forth between ValueTuple and CommandResult<TEntity, TError>.
In the past I joined the errorcode camp (did too much C programming). But now I have seen the light.
Yes exceptions are a bit of a burden on the system. But they simplify the code, reducing the number of errors (and WTF's).
So use exception but use them wise. And they will be your friend.
As a side note. I have learned to document which exception can be thrown by which method. Unfortunately this is not required by most languages. But it increases the chance of handling the right exceptions at the right level.
There may be a few situations where using exceptions in a clean, clear, correct way is cumbersome, but the vast majority of the time exceptions are the obvious choice. The biggest benefit exception handling has over error codes is that it changes the flow of execution, which is important for two reasons.
When an exception occurs, the application is no longer following it's 'normal' execution path. The first reason why this is so important is that unless the author of the code goes well and truly out of their way to be bad, the program will halt and not continue doing unpredictable things. If an error code doesn't get checked and appropriate actions aren't taken in response to a bad error code, the program will keep on doing what it's doing and who knows what the result of that action will be. There are lots of situations where having the program do 'whatever' could wind up being very expensive. Consider a program that retrieves performance information for various financial instruments a company sells, and delivers that information to brokers/wholesalers. If something goes wrong and the program keeps going, it could ship erroneous performance data to the brokers and wholesalers. I don't know about anybody else, but I don't want to be the one sitting in a VPs office explaining why my code caused the company to get 7-figures worth of regulatory fines. Delivering an error message to customers is generally preferable to delivering wrong data that could look to be 'real', and the latter situation is much easier to run into with a much less aggressive approach like error codes.
The second reason why I like exceptions and their breaking of the normal execution is that it makes it much, much easier to keep the 'normal things are happening' logic separate from the 'something went wrong logic'. To me, this:
try {
// Normal things are happening logic
catch (// A problem) {
// Something went wrong logic
}
...is preferable to this:
// Some normal stuff logic
if (errorCode means error) {
// Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
// Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
// Some stuff went wrong logic
}
There are other little things about exceptions that are nice, as well. Having a bunch of conditional logic to keep track of whether any of the methods being called in a function had an error code returned, and return that error code higher up is a lot of boiler plate. In fact, it's a lot of boiler plate that can go wrong. I have a lot more faith in the exception system of most languages than I do a rats nest of if-else-if-else statements that 'Fresh-out-of-college' Fred wrote, and I have a lot better things to do with my time than code reviewing said rat's nest.
My reasoning would be if you are writing a low-level driver that really needs performance, then use error codes. But if you're using that code in a higher-level application and it can handle a bit of overhead, then wrap that code with an interface which checks those error codes and raises exceptions.
In all other cases, exceptions are probably the way to go.
My approach is that we can use both, i.e. Exceptions and Errors codes at the same time.
I'm used to define several types of Exceptions (ex: DataValidationException or ProcessInterruptExcepion) and inside each exception define a more detailed description of each problem.
A Simple Example in Java:
public class DataValidationException extends Exception {
private DataValidation error;
/**
*
*/
DataValidationException(DataValidation dataValidation) {
super();
this.error = dataValidation;
}
}
enum DataValidation{
TOO_SMALL(1,"The input is too small"),
TOO_LARGE(2,"The input is too large");
private DataValidation(int code, String input) {
this.input = input;
this.code = code;
}
private String input;
private int code;
}
In this way i use Exceptions to define category errors, and error codes to define more detailed info about the problem.
I may be sitting on the fence here, but...
It depends on the language.
Whichever model you choose, be consistent about how you use it.
In Python, use of exceptions is standard practice, and I'm quite happy to define my own exceptions. In C you don't have exceptions at all.
In C++ (in the STL at least), exceptions are typically only thrown for truly exceptional errors (I virtually never see them myself). I see no reason to do anything different in my own code. Yes it's easy to ignore return values, but C++ doesn't force you to catch exceptions either. I think you just have to get into the habit of doing it.
The code base I work on is mostly C++ and we use error codes almost everywhere, but there's one module that raises exceptions for any error, including very unexceptional ones, and all the code that uses that module is pretty horrible. But that might just be because we've mixed exceptions and error codes. The code that consistently uses error codes is much easier to work with. If our code consistently used exceptions, maybe it wouldn't be as bad. Mixing the two doesn't seem to work so well.
Since I work with C++, and have RAII to make them safe to use, I use exceptions almost exclusively. It pulls error handling out of the normal program flow and makes the intent more clear.
I do leave exceptions for exceptional circumstances though. If I'm expecting that a certain error is going to happen a lot I'll check that the operation will succeed before performing it, or call a version of the function that uses error codes instead (Like TryParse())
Method signatures should communicate to you what the method does. Something like
long errorCode = getErrorCode();
might be fine, but
long errorCode = fetchRecord();
is confusing.
Exceptions are for exceptional circumstances - ie, when they are not part of the normal flow of the code.
It's quite legitimate to mix Exceptions and error codes, where error codes represent the status of something, rather than an error in the running of the code per se (e.g. checking the return code from a child process).
But when an exceptional circumstance occurs I believe Exceptions are the most expressive model.
There are cases where you might prefer, or have, to use error codes in place of Exceptions, and these have been adequately covered already (other than other obvious constrains such as compiler support).
But going in the other direction, using Exceptions allows you to build even higher level abstractions to your error handling, that can make your code even more expressive and natural. I would highly recommend reading this excellent, yet underrated, article by C++ expert Andrei Alexandrescu on the subject of what he calls, "Enforcements": http://www.ddj.com/cpp/184403864. Although it's a C++ article the principles are generally applicable, and I have translated the enforcements concept to C# quite successfully.
First, I agree with Tom's answer that for high-level stuff use exceptions, and for low-level stuff use error codes, as long as it is not Service Oriented Architecture (SOA).
In SOA, where methods may be called across different machines, exceptions may not be passed over the wire, instead, we use success/failure responses with a structure like below (C#):
public class ServiceResponse
{
public bool IsSuccess => string.IsNullOrEmpty(this.ErrorMessage);
public string ErrorMessage { get; set; }
}
public class ServiceResponse<TResult> : ServiceResponse
{
public TResult Result { get; set; }
}
And use like this:
public async Task<ServiceResponse<string>> GetUserName(Guid userId)
{
var response = await this.GetUser(userId);
if (!response.IsSuccess) return new ServiceResponse<string>
{
ErrorMessage = $"Failed to get user."
};
return new ServiceResponse<string>
{
Result = user.Name
};
}
When these are used consistently in your service responses it creates a very nice pattern of handling success/failures in the application. This allows easier error handling in async calls within services as well as across services.
I would prefer Exceptions for all error cases, except when a failure is an expectable bug-free result of a function that returns a primitive datatype. E.g. finding the index of a substring within a larger string would usually return -1 if not found, instead of raising a NotFoundException.
Returning invalid pointers that might be dereferenced (e.g. causing NullPointerException in Java) is not acceptable.
Using multiple different numerical error codes (-1, -2) as return values for the same function is usually bad style, as clients might do a "== -1" check instead of "< 0".
One thing to keep in mind here is the evolution of APIs over time. A good API allows to change and extend failure behavior in several ways without breaking clients. E.g. if a client error handle checked for 4 error cases, and you add a fifth error value to your function, the client handler may not test this and break. If you raise Exceptions, this will usually make it easier for clients to migrate to a newer version of a library.
Another thing to consider is when working in a team, where to draw a clear line for alldevelopers to make such a decision. E.g. "Exceptions for high-level stuff, error codes for low-level stuff" is very subjective.
In any case, where more than one trivial type of error is possible, the source code should never use the numeric literal to return an error code or to handle it (return -7, if x == -7 ...), but always a named constant (return NO_SUCH_FOO, if x == NO_SUCH_FOO) .
If you work under big project, you can't use only exceptions or only error codes. In different cases you should use different approaches.
For example, you decide to use exceptions only. But once you decide to use async event processing. It is bad idea to use exceptions for error handling in this situations. But use error codes everywhere in application is tedious.
So my opinion that it is normal to use both exceptions and error codes simultaneous.
For most applications, exceptions are better. The exception is when the software has to communicate with other devices. The domain I work in is industrial controls. Here errors codes are preferred and expected. So my answer is that it does depend on the situation.
I think it also depends on whether you really need information like stack trace from the result. If yes, you definitely go for Exception which provide object full with lots of information about problem. However, if you are just interested in result and don't care why that result then go for error code.
e.g. When you are processing file and face IOException, client might interested in knowing from where this was triggered, in opening file or parsing file etc. So better you return IOException or its specific subclass. However, scenario like you have login method and you want to know it was successful or not, there either you just return boolean or to show correct message, return error code. Here Client is not interested in knowing which part of logic caused that error code. He just know if its Credential invalid or account lock etc.
Another usecase I can think of is when data travels on network. Your remote method can return just error code instead of Exception to minimize data transfer.
My general rule is:
Only one error could appear in a function: use error code (as parameter of the function)
More than one specific error could appear: throw exception
Error codes also don't work when your method returns anything other than a numeric value...
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?
My personal guideline is: an exception is thrown when a fundamental assumption of the current code block is found to be false.
Example 1: say I have a function which is supposed to examine an arbitrary class and return true if that class inherits from List<>. This function asks the question, "Is this object a descendant of List?" This function should never throw an exception, because there are no gray areas in its operation - every single class either does or does not inherit from List<>, so the answer is always "yes" or "no".
Example 2: say I have another function which examines a List<> and returns true if its length is more than 50, and false if the length is less. This function asks the question, "Does this list have more than 50 items?" But this question makes an assumption - it assumes that the object it is given is a list. If I hand it a NULL, then that assumption is false. In that case, if the function returns either true or false, then it is breaking its own rules. The function cannot return anything and claim that it answered the question correctly. So it doesn't return - it throws an exception.
This is comparable to the "loaded question" logical fallacy. Every function asks a question. If the input it is given makes that question a fallacy, then throw an exception. This line is harder to draw with functions that return void, but the bottom line is: if the function's assumptions about its inputs are violated, it should throw an exception instead of returning normally.
The other side of this equation is: if you find your functions throwing exceptions frequently, then you probably need to refine their assumptions.
Because they're things that will happen normally. Exceptions are not control flow mechanisms. Users often get passwords wrong, it's not an exceptional case. Exceptions should be a truly rare thing, UserHasDiedAtKeyboard type situations.
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.
It is NOT an exception if the username is not valid or the password is not correct. Those are things you should expect in the normal flow of operation. Exceptions are things that are not part of the normal program operation and are rather rare.
I do not like using exceptions because you can not tell if a method throws an exception just by looking at the call. Thats why exceptions should only be used if you can't handle the situation in a decent manner (think "out of memory" or "computer is on fire").
One rule of thumb is to use exceptions in the case of something you couldn't normally predict. Examples are database connectivity, missing file on disk, etc. For scenarios that you can predict, ie users attempting to log in with a bad password you should be using functions that return booleans and know how to handle the situation gracefully. You don't want to abruptly end execution by throwing an exception just because someone mistyped their password.
Others propose that exceptions should not be used because the bad login is to be expected in a normal flow if the user mistypes. I disagree and I don't get the reasoning. Compare it with opening a file.. if the file doesn't exist or is not available for some reason then an exception will be thrown by the framework. Using the logic above this was a mistake by Microsoft. They should have returned an error code. Same for parsing, webrequests, etc., etc..
I don't consider a bad login part of a normal flow, it's exceptional. Normally the user types the correct password, and the file does exist. The exceptional cases are exceptional and it's perfectly fine to use exceptions for those. Complicating your code by propagating return values through n levels up the stack is a waste of energy and will result in messy code. Do the simplest thing that could possibly work. Don't prematurely optimize by using error codes, exceptional stuff by definition rarely happens, and exceptions don't cost anything unless you throw them.
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.
Exceptions are a somewhat costly effect, if for example you have a user that provides an invalid password, it is typically a better idea to pass back a failure flag, or some other indicator that it is invalid.
This is due to the way that exceptions are handled, true bad input, and unique critical stop items should be exceptions, but not failed login info.
I would say there are no hard and fast rules on when to use exceptions. However there are good reasons for using or not using them:
Reasons to use exceptions:
The code flow for the common case is clearer
Can return complex error information as an object (although this can also be achieved using error "out" parameter passed by reference)
Languages generally provide some facility for managing tidy cleanup in the event of the exception (try/finally in Java, using in C#, RAII in C++)
In the event no exception is thrown, execution can sometimes be faster than checking return codes
In Java, checked exceptions must be declared or caught (although this can be a reason against)
Reasons not to use exceptions:
Sometimes it's overkill if the error handling is simple
If exceptions are not documented or declared, they may be uncaught by calling code, which may be worse than if the the calling code just ignored a return code (application exit vs silent failure - which is worse may depend on the scenario)
In C++, code that uses exceptions must be exception safe (even if you don't throw or catch them, but call a throwing function indirectly)
In C++, it is hard to tell when a function might throw, therefore you must be paranoid about exception safety if you use them
Throwing and catching exceptions is generally significantly more expensive compared to checking a return flag
In general, I would be more inclined to use exceptions in Java than in C++ or C#, because I am of the opinion that an exception, declared or not, is fundamentally part of the formal interface of a function, since changing your exception guarantee may break calling code. The biggest advantage of using them in Java IMO, is that you know that your caller MUST handle the exception, and this improves the chance of correct behaviour.
Because of this, in any language, I would always derive all exceptions in a layer of code or API from a common class, so that calling code can always guarantee to catch all exceptions. Also I would consider it bad to throw exception classes that are implementation-specific, when writing an API or library (i.e. wrap exceptions from lower layers so that the exception that your caller receives is understandable in the context of your interface).
Note that Java makes the distinction between general and Runtime exceptions in that the latter need not be declared. I would only use Runtime exception classes when you know that the error is a result of a bug in the program.
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.
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.
the rule of thumb for throwing exceptions is pretty simple. you do so when your code has entered into an UNRECOVERABLE INVALID state. if data is compromised or you cannot wind back the processing that occurred up to the point then you must terminate it. indeed what else can you do? your processing logic will eventually fail elsewhere. if you can recover somehow then do that and do not throw exception.
in your particular case if you were forced to do something silly like accept money withdrawal and only then check user/pasword you should terminate the process by throwing an exception to notify that something bad has happened and prevent further damage.
I agree with japollock way up there--throw an acception when you are uncertain about the outcome of an operation. Calls to APIs, accessing filesystems, database calls, etc. Anytime you are moving past the "boundaries" of your programming languages.
I'd like to add, feel free to throw a standard exception. Unless you are going to do something "different" (ignore, email, log, show that twitter whale picture thingy, etc), then don't bother with custom exceptions.
I'd say that generally every fundamentalism leads to hell.
You certainly wouldn't want to end up with exception driven flow, but avoiding exceptions altogether is also a bad idea. You have to find a balance between both approaches. What I would not do is to create an exception type for every exceptional situation. That is not productive.
What I generally prefer is to create two basic types of exceptions which are used throughout the system: LogicalException and TechnicalException. These can be further distinguished by subtypes if needed, but it is not generally not necessary.
The technical exception denotes the really unexpected exception like database server being down, the connection to the web service threw the IOException and so on.
On the other hand the logical exceptions are used to propagate the less severe erroneous situation to the upper layers (generally some validation result).
Please note that even the logical exception is not intended to be used on regular basis to control the program flow, but rather to highlight the situation when the flow should really end. When used in Java, both exception types are RuntimeException subclasses and error handling is highly aspect oriented.
So in the login example it might be wise to create something like AuthenticationException and distinguish the concrete situations by enum values like UsernameNotExisting, PasswordMismatch etc. Then you won't end up in having a huge exception hierarchy and can keep the catch blocks on maintainable level. You can also easily employ some generic exception handling mechanism since you have the exceptions categorized and know pretty well what to propagate up to the user and how.
Our typical usage is to throw the LogicalException during the Web Service call when the user's input was invalid. The Exception gets marshalled to the SOAPFault detail and then gets unmarshalled to the exception again on the client which is resulting in showing the validation error on one certain web page input field since the exception has proper mapping to that field.
This is certainly not the only situation: you don't need to hit web service to throw up the exception. You are free to do so in any exceptional situation (like in the case you need to fail-fast) - it is all at your discretion.
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.
Firstly, if the users of your API aren't interested in specific, fine-grained failures, then having specific exceptions for them isn't of any value.
Since it's often not possible to know what may be useful to your users, a better approach is to have the specific exceptions, but ensure they inherit from a common class (e.g., std::exception or its derivatives in C++). That allows your client to catch specific exceptions if they choose, or the more general exception if they don't care.
Exceptions are intended for events that are abnormal behaviors, errors, failures, and such. Functional behavior, user error, etc., should be handled by program logic instead. Since a bad account or password is an expected part of the logic flow in a login routine, it should be able to handle those situations without exceptions.
The simple answer is, whenever an operation is impossible (because of either application OR because it would violate business logic). If a method is invoked and it impossible to do what the method was written to do, throw an Exception. A good example is that constructors always throw ArgumentExceptions if an instance cannot be created using the supplied parameters. Another example is InvalidOperationException, which is thrown when an operation cannot be performed because of the state of another member or members of the class.
In your case, if a method like Login(username, password) is invoked, if the username is not valid, it is indeed correct to throw a UserNameNotValidException, or PasswordNotCorrectException if password is incorrect. The user cannot be logged in using the supplied parameter(s) (i.e. it's impossible because it would violate authentication), so throw an Exception. Although I might have your two Exceptions inherit from ArgumentException.
Having said that, if you wish NOT to throw an Exception because a login failure may be very common, one strategy is to instead create a method that returns types that represent different failures. Here's an example:
{ // class
...
public LoginResult Login(string user, string password)
{
if (IsInvalidUser(user))
{
return new UserInvalidLoginResult(user);
}
else if (IsInvalidPassword(user, password))
{
return new PasswordInvalidLoginResult(user, password);
}
else
{
return new SuccessfulLoginResult();
}
}
...
}
public abstract class LoginResult
{
public readonly string Message;
protected LoginResult(string message)
{
this.Message = message;
}
}
public class SuccessfulLoginResult : LoginResult
{
public SucccessfulLogin(string user)
: base(string.Format("Login for user '{0}' was successful.", user))
{ }
}
public class UserInvalidLoginResult : LoginResult
{
public UserInvalidLoginResult(string user)
: base(string.Format("The username '{0}' is invalid.", user))
{ }
}
public class PasswordInvalidLoginResult : LoginResult
{
public PasswordInvalidLoginResult(string password, string user)
: base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
{ }
}
Most developers are taught to avoid Exceptions because of the overhead caused by throwing them. It's great to be resource-conscious, but usually not at the expense of your application design. That is probably the reason you were told not to throw your two Exceptions. Whether to use Exceptions or not usually boils down to how frequently the Exception will occur. If it's a fairly common or an fairly expectable result, this is when most developers will avoid Exceptions and instead create another method to indicate failure, because of the supposed consumption of resources.
Here's an example of avoiding using Exceptions in a scenario like just described, using the Try() pattern:
public class ValidatedLogin
{
public readonly string User;
public readonly string Password;
public ValidatedLogin(string user, string password)
{
if (IsInvalidUser(user))
{
throw new UserInvalidException(user);
}
else if (IsInvalidPassword(user, password))
{
throw new PasswordInvalidException(password);
}
this.User = user;
this.Password = password;
}
public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
{
if (IsInvalidUser(user) ||
IsInvalidPassword(user, password))
{
return false;
}
validatedLogin = new ValidatedLogin(user, password);
return true;
}
}
for me Exception should be thrown when a required technical or business rule fails.
for instance if a car entity is associated with array of 4 tires ... if one tire or more are null ... an exception should be Fired "NotEnoughTiresException" , cuz it can be caught at different level of the system and have a significant meaning through logging.
besides if we just try to flow control the null and prevent the instanciation of the car .
we might never never find the source of the problem , cuz the tire isn't supposed to be null in the first place .
the main reason for avoiding throwing an exception is that there is a lot of overhead involved with throwing an exception.
One thing the article below states is that an exception is for an exceptional conditions and errors.
A wrong user name is not necessarily a program error but a user error...
Here is a decent starting point for exceptions within .NET:
http://msdn.microsoft.com/en-us/library/ms229030(VS.80).aspx
Throwing exceptions causes the stack to unwind, which has some performance impacts (admitted, modern managed environments have improved on that). Still repeatedly throwing and catching exceptions in a nested situation would be a bad idea.
Probably more important than that, exceptions are meant for exceptional conditions. They should not be used for ordinary control flow, because this will hurt your code's readability.
I have three type of conditions that I catch.
Bad or missing input should not be an exception. Use both client side js and server side regex to detect, set attributes and forward back to the same page with messages.
The AppException. This is usually an exception that you detect and throw with in your code. In other words these are ones you expect (the file does not exist). Log it, set the message, and forward back to the general error page. This page usually has a bit of info about what happened.
The unexpected Exception. These are the ones you don't know about. Log it with details and forward them to a general error page.
Hope this helps
Security is conflated with your example: You shouldn't tell an attacker that a username exists, but the password is wrong. That's extra information you don't need to share. Just say "the username or password is incorrect."
I have philosophical problems with the use of exceptions. Basically, you are expecting a specific scenario to occur, but rather than handling it explicitly you are pushing the problem off to be handled "elsewhere." And where that "elsewhere" is can be anyone's guess.
To my mind, the fundamental question should be whether one would expect that the caller would want to continue normal program flow if a condition occurs. If you don't know, either have separate doSomething and trySomething methods, where the former returns an error and the latter does not, or have a routine that accepts a parameter to indicate whether an exception should be thrown if it fails). Consider a class to send commands to a remote system and report responses. Certain commands (e.g. restart) will cause the remote system to send a response but then be non-responsive for a certain length of time. It is thus useful to be able to send a "ping" command and find out whether the remote system responds in a reasonable length of time without having to throw an exception if it doesn't (the caller would probably expect that the first few "ping" attempts would fail, but one would eventually work). On the other hand, if one has a sequence of commands like:
exchange_command("open tempfile");
exchange_command("write tempfile data {whatever}");
exchange_command("write tempfile data {whatever}");
exchange_command("write tempfile data {whatever}");
exchange_command("write tempfile data {whatever}");
exchange_command("close tempfile");
exchange_command("copy tempfile to realfile");
one would want failure of any operation to abort the whole sequence. While one could check each operation to ensure it succeeded, it's more helpful to have the exchange_command() routine throw an exception if a command fails.
Actually, in the above scenario it may be helpful to have a parameter to select a number of failure-handling modes: never throw exceptions, throw exceptions for communication errors only, or throw exceptions in any cases where a command does not return a "success" indication.
You may use a little bit generic exceptions for that conditions. For e.g. ArgumentException is meant to be used when anything goes wrong with the parameters to a method (with the exception of ArgumentNullException). Generally you would not need exceptions like LessThanZeroException, NotPrimeNumberException etc. Think of the user of your method. The number of the conditions that she will want to handle specifically is equal to the number of the type of the exceptions that your method needs to throw. This way, you can determine how detailed exceptions you will have.
By the way, always try to provide some ways for users of your libraries to avoid exceptions. TryParse is a good example, it exists so that you don't have to use int.Parse and catch an exception. In your case, you may want to provide some methods to check if user name is valid or password is correct so your users (or you) will not have to do lots of exception handling. This will hopefully result in more readble code and better performance.
Ultimately the decision comes down to whether it is more helpful to deal with application-level errors like this using exception handling, or via your own home-rolled mechanism like returning status codes. I don't think there's a hard-and-fast rule about which is better, but I would consider:
Who's calling your code? Is this a public API of some sort or an internal library?
What language are you using? If it's Java, for example, then throwing a (checked) exception puts an explicit burden on your caller to handle this error condition in some way, as opposed to a return status which could be ignored. That could be good or bad.
How are other error conditions in the same application handled? Callers won't want to deal with a module that handles errors in an idiosyncratic way unlike anything else in the system.
How many things can go wrong with the routine in question, and how would they be handled differently? Consider the difference between a series of catch blocks that handle different errors and a switch on an error code.
Do you have structured information about the error you need to return? Throwing an exception gives you a better place to put this information than just returning a status.
Some useful things to think about when deciding whether an exception is appropriate:
what level of code you want to have run after the exception candidate occurs - that is, how many layers of the call stack should unwind. You generally want to handle an exception as close as possible to where it occurs. For username/password validation, you would normally handle failures in the same block of code, rather than letting an exception bubble up. So an exception is probably not appropriate. (OTOH, after three failed login attempts, control flow may shift elsewhere, and an exception may be appropriate here.)
Is this event something you would want to see in an error log? Not every exception is written to an error log, but it's useful to ask whether this entry in an error log would be useful - i.e., you would try to do something about it, or would be the garbage you ignore.
"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.
I would say that exceptions should be thrown if an unexpected behaviour is occuring that wasnt meant to be.
Like trying to update or delete a non existing entity. And it should be catched where the Exception can be handled and has meaning. For working in an alternative way to continue, add logging or returning a specific result on Api level.
If you expect something to be the case, you should build code to check and ensure it.