First of all, I know the standard answer will be that exceptions are never to be used for flow control. While I perfectly agree with this, I've been thinking a long time about something I sometimes did, which I'll describe with the following pseudo-code:
try
string keyboardInput = read()
int number = int.parse(keyboardInput)
//the conversion succeeds
if(number >= 1000)
//That's not what I asked for. The message to display to the user
//is already in the catch-block below.
throw new NumberFormatException() //well, there IS something wrong with the number...
catch(NumberFormatException ex) //the user entered text
print("Please enter a valid number below 1000.")
First of all, take this example in a very abstract way. This does not necessarily have to happen. The situation simply is:
A user input needs to be constrained and can go wrong in 2 ways,
either
by a thrown exception the language defines, or by a check. Both errors
are reported by the user in the same way, because they do not need to know
the technical difference of what caused it.
I have thought of several ways to solve it. To begin with, it would be better to throw a custom made exception. The problem I then face is, if I catch it locally, what to do with the other exception? In se, the custom exception would be cause for a second catch-block, in which the message would be copied into just as well. My solution:
//number is wrong
throw new MyException()
catch(NumberFormatException ex)
throw new MyException()
catch(MyException ex) {
print("Please enter...")
The meaning of the exceptions' names is everything here. This application of custom-made exceptions is widely accepted, but essentially I didn't do anything different from the first way: I forced to go into a catch-block, albeit by throwing a custom exception rather than a standard-library one.
The same way applied to throwing the exception on to the calling method (thus not having a catch block for the custom exception) seems to make more sense. My method can go wrong in what is technically two ways, but essentially one way: wrong user input. Therefore, one would write a UserInputException and make the method throw this. New problem: what if this is the main method of an application?
I'm not currently struggling with a specific application to implement this kind of behaviour, my question is purely theoretical and non-language specific.
What is the best way to approach this?
I would consider the first exception to be low-level, and I would handle it (by translation in this case) at the point of call. I find that this leads to code that is easier to maintain and refactor later, as you have less types of exceptions to handle.
try
string keyboardInput = read()
try
int number = int.parse(keyboardInput)
catch(NumberFormatException ex)
throw MyException("Input value was not a number")
//the conversion succeeds
if(number >= 1000)
throw MyException("Input value was out of range")
catch(MyException ex) //the user entered text
print( ex.ToString() )
print("Please enter a valid number below 1000.")
I think you have essentially a few ways to go about it with minimal code duplication in mind:
Use a boolean variable/store the exception: If there was an error anywhere in the the general logic of the specific task you are performing, you exit on the first sign of error and handle that in a separate error handling branch.
Advantages: only one place to handle the error; you can use any custom exception/error condition you like.
Disadvantages: the logic of what you are trying to achieve might be hard to discover.
Create a general function that you can use to inform the user about the error (pre-calculating/storing all information that describes the general error, e.g. the message to display the user), so you can just make one function call when an error condition happens.
Advantages: the logic of your intent might be clearer for readers of the code; you can use anu custom exception/error conditon you like.
Disadvantages: the error will have to be handled in separate places (although with the pre-computed/stored values, there is not much copy-paste, however complex the informing the user part).
If the intent is clear, I don't think throwing exceptions from within your try block explicitly is a bad idea. If you do not want to throw one of the system provided exceptions, you can always create your own that derives from one of them, so you only need a minimal number (preferably one) of catch blocks.
Advantages: only one place to handle error condition -- if there is essentially only one type of exception thrown in try-block.
Disadvantages: if more than one type of exception is thrown, you need nested try-catch blocks (to propagate the exceptions to the most outward one) or a very general (e.g. Exception) catch block to avoid having to duplicate error reporting.
The way I see it is this:
Assuming there's no other way to parse your int that doesn't throw an exception, your code as it is now, is correct and elegant.
The only issue would be if your code was in some kind of loop, in which case you might worry about the overhead of throwing and catching unnecessary exceptions. In that case, you will have to compromise some of your code's beauty in favor of only handling exceptions whenever necessary.
error=false;
try {
string keyboardInput = read();
int number = int.parse(keyboardInput);
//the conversion succeeds
if(number >= 1000) {
//That's not what I asked for. The message to display to the user
//is already in the catch-block below.
error=true;
} catch(NumberFormatException ex) { //the user entered text
error=true;
}
if (error)
print("Please enter a valid number below 1000.");
Also you can think about why you're trying to aggregate two errors into one.
Instead you could inform the user as to what error they did, which might be more helpful in some cases:
try {
string keyboardInput = read();
int number = int.parse(keyboardInput);
//the conversion succeeds
if(number >= 1000) {
//That's not what I asked for. The message to display to the user
//is already in the catch-block below.
print("Please enter a number below 1000.");
} catch(NumberFormatException ex) { //the user entered text
print("Please enter a valid number.");
}
You do not need any exceptions in this particular example.
int number;
if (int.TryParse(keyboardInput, out number) && number < 1000) // success
else // error
However, the situation you describe is common in business software, and throwing an exception to reach a uniform handler is quite common.
One such pattern is XML validation followed by XSLT. In some systems, invalid XML is handled through catching validation exceptions. In these systems, it is pretty natural to reuse the existing exception handling in XSLT (which can naturally detect some classes of data errors that a particular validation language cannot):
<xsl:if test="#required = 'yes' and #prohibited = 'yes'>
<xsl:message terminate='yes'>Error message</xsl:message>
</xsl:if>
It is important to see that if such conditions are extremely rare (expected to occur only during early integration testing, and disappear as defects in other modules get fixed), most of the typical concerns around not using exceptions for flow control do not really apply.
What about approaching this validation problem by writing several validator classes that take in an input and return errors, or no errors. As far as your struggle with exceptions: put that logic into each validator and deal with it there on a case by case basis.
after that you figure out the correct validators to use for your input, collect their errors and handle them.
the benefits of this are:
Validators do one thing, validate a single case
Its up to the validation function to decide how to handle the errors. Do you break on first validation error or do you collect them all and then deal with them?
You can write your code is such a way that the main validation function can validate different types of input using the same code, just picking the correct validators using your favorite technique.
and disadvantages:
You will end up writing more code (but if you are using java, this should be put into the 'benefits' bucket)
here is some example pseudo-code:
validate(input):
validators = Validator.for(input.type)
errors = []
for validator in validators:
errors.push(validator.validate(input))
if errors:
throw PoopException
and some validators:
MaxValidator extends IntValidator:
validate(input):
errors = []
errors.push(super.validate(input))
if input > 1000:
errors.push("bleee!!!! to big!")
return errors
IntValidator:
validate(input):
try:
int.parse(input)
catch NumberFormatException:
return ['not an int']
return []
of course you would need to do some trickery to make the parent validator possibly return you a valid version of the input, in this case string "123" converted to an int so the max validator can handle it, but this can be easily accomplished by making the validators statefull or some other magic.
I can't see this answer anywhere in here, so I'll just post it as another point of view.
As we all know, you can actually break the rules if you know them well enough, so you can use throwing an Exception for flow control if you know it's the best solution for your situation. From what I've seen, it happens usually with some dumb frameworks...
That said, before Java 7 (which brought us the mighty multicatch construct), this was my approach to avoid code repetition:
try {
someOffendingMethod();
} catch (Exception e) {
if (e instanceof NumberFormatException || e instanceof MyException) {
System.out.println("Please enter a valid number.");
}
}
It's a valid technique in C#, too.
Related
For example, in the case of "The array index out of bound" exception, why don't we check the array length in advance:
if(array.length < countNum)
{
//logic
}
else
{
//replace using exception
}
My question is, why choose to use an exception? and when to use an exception, instead of if-else
Thanks.
It depends on acceptable practices for a given language.
In Java, the convention is to always check conditions whenever possible and not to use exceptions for flow control. But, for example, in Python not only using exception in this manner is acceptable, but it is also a preferred practice.
They are used to inform the code that calls your code an exceptional condition occurred. Exceptions are more expensive than well formed if/else logic so you use them in exceptional circumstances such as reaching a condition in your code you cannot handle locally, or to support giving the caller of your code the choice of how to handle the error condition.
Usually if you find yourself throwing and catching exceptions in your own function or method, you can probably find a more efficient way of doing it.
There are many answers to that question. As a single example, from Java, when you are using multiple threads, sometimes you need to interrupt a thread, and the thread will see this when an InterruptedException is thrown.
Other times, you will be using an API that throws certain exceptions. You won't be able to avoid it. If the API throws, for example, an IOException, then you can catch it, or let it bubble up.
Here's an example where it would actually be better to use an exception instead of a conditional.
Say you had a list of 10,000 strings. Now, you only want those items which are integers. Now, you know that a very small number of them won't be integers (in string form). So should you check to see if every string is an integer before trying to convert them? Or should you just try to convert them and throw and catch an exception if you get one that isn't an integer? The second way is more efficient, but if they were mostly non-integers then it would be more efficient to use an if-statement.
Most of the time, however, you should not use exceptions if you can replace them with a conditional.
As someone has already said, 'Exceptions' in programming languages are for exceptional cases and not to set logical flow of your program. For example, in the case of given code snippet of your question, you have to see what the enclosing method's or function's intention is. Is checking array.length < countNum part of the business logic or not. If yes, then putting a pair of if/else there is the way to go. If that condition is not part of the business logic and the enclosing method's intention is something else, then write code for that something else and throw exception instead of going the if/else way. For example you develop an application for a school and in your application you have a method GetClassTopperGrades which is responsible for the business logic part which requires to return the highest marks of the student in a certain class. the method/function definition would be something like this:
int GetClassTopperGrades(string classID)
In this case the method's intention is to return the grades, for a valid class, which will always be a positive integer, according to the business logic of the application. Now if someone calls your method and passes a garbage string or null, what should it do? If should throw an exception e.g. ArgumentException or 'ArgumentNullException' because this was an exceptional case in this particular context. The method assumed that always a valid class ID will be passed and NULL or empty string is NOT a valid class ID (a deviation from the business logic).
Apart from that, in some conditions there is no prior knowledge about the outcome of a given code and no defined way to prevent an exceptional situation. For example, querying some remote database, if the network goes down, you don't have any other option there apart from throwing an exception. Would you check network connectivity before issuing every SQL query to the remote database?
There is strong and indisputable reason why to use exceptions - no matter of language. I strongly believe that decision about if to use exceptions or not have nothing to do with particular language used.
Using exceptions is universal method to notify other part of code that something wrong happened in kind of loosely coupled way. Let imagine that if you would like to handle some exceptional condition by using if.. nad else.. you need to insert into different part of your code some arbitrary variables and other stuff which probably would easily led to have spaghetti code soon after.
Let next imagine that you are using any external library/package and it's author decided to put in his/her code other arbitrary way to handle wrong states - it would force you to adjust to its way of dealing with it - for example you would need to check if particular methods returns true or false or whatever. Using exceptions makes handling errors much more easy - you just assume that if something goes wrong - the other code will throw exception, so you just wrap the code in try block and handle possible exception on your own way.
This is a general programming question, not pertaining to any specific language.
A new programmer typically will write a method that calculates some value, then returns the value:
public Integer doSomething()
{
// Calculate something
return something;
}
public void main()
{
Integer myValue = doSomething();
}
But when an exception occurs during the calculation of something, what is the best way to handle the exception, especially when giving the user feedback? If you do a try/catch of the calculation of something and if an exception is caught, what do you return? Nothing was calculated, so do you return null? And once you return it (whatever it may be), do you need to do another try/catch in the parent method that checks to see if a valid value was returned? And if not, then make sure the user is given some feedback?
I have heard arguments on both sides of the table about never returning values at all, but instead setting calculated values as pointers or global variables and instead returning only error codes from methods, and then (in the parent method) simply handling the error codes accordingly.
Is there a best practice or approach to this? Are there any good resources that one could access to learn more about the best way to handle this?
UPDATE for Clarification
Consider the following code:
public void main()
{
int myValue = getMyValue();
MyUIObject whatever = new MyUIObject();
whatever.displayValue(myValue); // Display the value in the UI or something
}
public Integer getMyValue()
{
try
{
// Calculate some value
} catch (exception e) {
// ??
}
return value;
}
I call the method to get some int value, then I return it. Back in main(), I do something with the value, like show it in the Log in this case. Usually I would display the value in the UI for the user.
Anyways, if an exception is caught in getMyValue(), so does value get returned but it's null? What happens in main() then? Do I have to test if it's a valid value in main() as well?
I need the program to handle the error accordingly and continue. Someone below suggested displaying the appropriate information in the UI from within the getMyValue() method. I see two potential issues:
It seems like I would be mixing the business logic with (in this case) the logic for the UI.
I would have to pass a reference of the MyUIObject to the getMyValue() or something so I could access it from within the function. In the above simple example that is no big deal, but if there is a BUNCH of UI elements that need to be updated or changed based off of what happens in getMyValue(), passing them all might be a bit much...
I've read a bunch about the fundamentals of all of this but I can't seem to find a straight answer for the above situation. I appreciate any help or insight.
I think you do not quite understand exceptions.
If you throw an exception, you do not return from the function normally:
public Integer doSomething()
{
throw new my_exception();
// The following code does NOT get run
return something;
}
public void main()
{
Integer myValue = doSomething();
}
The main advantages of exceptions are:
You can write your code as though everything is succeeding, which is usually clearer
Exceptions are hard to ignore. If an exception is unhandled, typically an obvious and loud error will be given, with a stack trace. This contrasts with error codes, where it is much easier to ignore the error handling than not.
I recommend this post by Eric Lippert, which discusses exceptions and when it is and is not appropriate to handle them.
UPDATE (in response to comment):
You can absolutely handle an exception and continue, you do this by catching the exception.
eg:
try
{
// Perform calculation
}
catch (ExceptionType ex)
{
// A problem of type 'ExceptionType' occurred - you can do whatever you
// want here.
// You could log it to a list, which will be later shown to the user,
// you could set a flag to pop up a dialog box later, etc
}
// The code here will still get run even if ExceptionType was thrown inside
// the try {} block, because we caught and handled that exception.
The nice thing about this is that you know what kind of thing went wrong (from the exception type), as well as details (by looking into the information in ex), so you
hopefully have the information you need to do the right thing.
UPDATE 2 in response to your edit:
You should handle the exception at the layer where you are able to respond in the way you want. For your example, you are correct, you should not be catching the exception so deep down in the code, since you don't have access to the UI, etc and you thus can't really do anything useful.
How about this version of your example code:
public void main()
{
int myValue = -1; // some default value
String error = null; // or however you do it in Java (:
try
{
getMyValue();
}
catch (exception e)
{
error = "Error calculating value. Check your input or something.";
}
if (error != null)
{
// Display the error message to the user, or maybe add it to a list of many
// errors to be displayed later, etc.
// Note: if we are just adding to a list, we could do that in the catch().
}
// Run this code regardless of error - will display default value
// if there was error.
// Alternatively, we could wrap this in an 'else' if we don't want to
// display anything in the case of an error.
MyUIObject whatever = new MyUIObject();
whatever.displayValue(myValue); // Display the value in the UI or something
}
public Integer getMyValue()
{
// Calculate some value, don't worry about exceptions since we can't
// do anything useful at this level.
return value;
}
Exceptions is a property of object oriented languages (OOL). If you use OOL, you should prefer exceptions. It is much better than to return error codes. You can find nice examples how the error-codes approach generates a vastly longer source code than exceptions based code. For example if you want to read a file and do something with it and save in a different format. You can do it in C without exceptions, but your code will be full of if(error)... statements, maybe you will try to use some goto statements, maybe some macros to make it shorter. But also absolutely nontransparent and hard to understand. Also you can often simply forget to test the return value so you don't see the error and program goes on. That's not good. On the other hand if you write in OOL and use exceptions, your source code focuses on "what to do when there is no error", and error handling is in a different place. Just one single error handling code for many possible file errors. The source code is shorter, more clear etc.
I personally would never try to return error codes in object oriented languages. One exception is C++ where the system of exceptions have some limitations.
You wrote:
I have heard arguments on both sides of the table about never returning values at all, but instead setting calculated values as pointers or global variables and instead returning only error codes from methods, and then (in the parent method) simply handling the error codes accordingly.
[EDIT]
Actually, excetion can be seen as error code, which comes along with the relative message, and you as the programmer should know where your exception must be caught, handled and eventually display to the user. As long as you let the exception to propagate (going down in the stack of called functions) no return values are used, so you don't have to care about handling related missed values. Good exception handling is a quite tough issue.
As jwd replied, I don't see the point to raise an exception in a method and then handle the excpetion in the same method just to return an error value. To clarify:
public Integer doSomething(){
try{
throw new my_exception();}
catch{ return err_value;}
}
is pointless.
//
// To Throw
void PrintType(object obj)
{
if(obj == null)
{
throw new ArgumentNullException("obj")
}
Console.WriteLine(obj.GetType().Name);
}
//
// Not to Throw
void PrintType(object obj)
{
if(obj != null)
{
Console.WriteLine(obj.GetType().Name);
}
}
What principle to keep?
Personally I prefer the first one its say developer-friendly(notified about each "anomaly").
The second one its say user-friendly(let user continue work even if "inside" not everything does right).
I think that is more complicated to find errors and bugs in the maintenance phase when you silently let the things to go on. If something goes wrong you are not notified at once, and sometimes have errors far away from the main error cause, and spend a lot of time to find it.
What do you think?
The second one is lethal. Failing silently is always the wrong thing to do. Suppose this were the banking system in the bank that holds your account. Would you like it if there was a problem paying in your salary and the system silently ignored it?
If the method body handles the null obj properly (in other words, obj != null is not a requirement), then there's no need to throw an exception.
In all other cases: Throw. Let the client take responsibility for their flawed input.
Throwing an exception (if null is an error) seems far better than silently ignoring an error.
There is a third option you can consider:
void PrintType(object obj)
{
Console.WriteLine(obj.GetType().Name);
}
This also throws an exception when obj is null. The advantage of this, is that less code is involved. The disadvantage of this approach is that it is more difficult to tell whether obj can be null.
Throw.
Let the caller of a function determine if it is important enough to throw an exception to the user on a null value, but the function itself should throw because of the invalid argument.
I'd say that it depends on your (developer) preference. From the user perspective, he should never see an unhandled exception, but it does not mean you cannot use exceptions.
I prefer the first one, because I find null to be a totally unnecessary (and annoying) construct, so I make effort to code without it. If there is a null somewhere, someone made a mistake, so the best thing is to just barf out instead of pretending everything is ok.
In the end it depends on what you consider to be the semantics of the method. If the method is supposed to accept nulls, then you should pick option number two. If the method is supposed to only accept real arguments (which I prefer), then you should pick option number one.
Always Throw, except in debugging/diagnostic code. It is most embarassing to have a NullPointerException that occurs in production code at a point where only a debugging message should be generated, e.g.
log.debug("id of object is " + obj.getId())
where the logger is turned off, and obj is null.
It is highly subjective, but I always prefer to just ignore non-fatal or recoverable errors. Put them in logs, if you must, but if you know how to continue - please do so.
Note, that when I say fatal, it actually depends on the function itself. Say, there's API function that gets ID and handful of other parameters. Suppose, that this ID also can be guessed from those other stuff that is passed in. API function should guess it if it can but the function somewhere inside that does all the work should get non-null ID and throw otherwise. Because for high level API function it is not fatal, it knows how to guess it, but for low level function it is fatal, it supposed to do something with that ID and with null value it can't continue.
All fatal errors should be noted, of course.
If you api if exposed outside, do always argument checking and throw a argument based exception so the api user can get the result.
Consider using the Null Object pattern is very useful to not clutter your code with try-catch, null checks (or god forbid swallowed errors).
In this particular example, giving nothing to a printer is like saying "print nothing", thus working as it should.
I do know this is an example, but it's just to clarify that this is relative.
If your code displays user-friendly messages on exceptions somehow, what difference does it make ? the first one would be both developer and user friendly.
It really depends on what your invariants are. If the parameter is optiona, then ignoring a null parameter is just fine, but if the parameter is required then that will hide a bug in your application. Also, and depending on the language, if the invariant is bad enough you may consider a third option: abort the application.
All discussions on whether to use or not exceptions can always be mapped to the decision on whether the situation is exceptional or not, and if it is exceptional, throwing or rather aborting the application depends on whether it is recoverable or not.
Id go for
void PrintType(object obj)
{
Console.WriteLine(obj.GetType().Name);
}
Third option, half in pseudocode:
// To Throw A Clean Error
void PrintType(object obj)
{
if(obj == null)
{
throw new ArgumentNullException(STANDARD_ERROR_MESSAGE, obj)
}
Console.WriteLine(obj.GetType().Name);
}
Either catch all errors and wrap them in a single place, so the user sees standard text:
There has been an error. If this error
persists, please contact an
administrator.
Or throw a select few errors, all of which are user-friendly, and display them directly to the user. "A connection error has occurred." "An authentication error has occurred." "A system error has occurred." And so on.
On the backend, have all errors and their stack trace logged, so you can use the debugging information that way.
It really depends on what the function is defined to do. The most important aspect is to have a clearly defined behavior and for the function to implement it correctly.
Now, if the question is whether is better to define the function to accept null and print it out, or to not accept it and throw an exception, I would say the latter, because it's probably less error prone for the user to check for null before calling the function, if that is a possibility.
This is a refactoring question.
try
{
string line = GetFirstLineFromFile(); //Gets first line from a text file, this line would be a number.
int value = ConvertToInteger(line); // Gets the integer value from the string.
int result = DivideByValue(value); // Divides some number with the value retrieved.
}
catch(Exception ex)
{
}
My main concern is, what is the best approach for exception handling in such situations. Certainly wrapping the whole thing in a single try catch is like saying I expect an exception about everything. There must be some place we catch a generic exception right?
Just don't catch a "generic exception".
How can you possibly handle ANY exception and know how to keep your application in a clean state ?
It hides bugs and it's a really bad idea.
Read this serie of posts on catch (Exception).
You need to think about what exceptions can be thrown from the methods in the try block, as well as which ones of those you can deal with at the current level of abstraction.
In your case, I'd expect that the getFirstLineFromFile methods, for example, can definitely throw exceptions you'd want to catch here. Now whether you wrap and rethrow the exception, or take other action, depends on whether you can actually deal with the exception at this level. Consider the case where you have a default file you can fall back to - the approach may just be to log a warning and continue with the default. Or if the whole application is based on reading a file supplied by the user, then this is more likely to be a fatal exception that should be propagated up to the top level and communicated to the user there.
There's no hard-and-fast rule like "always throw" or "never throw"; in general, I consider that one should throw exceptions whenever there's an exceptional-type situation that is not considered a normal result of the method, and consequently cannot be adequately described by the return type of the method. (For example, an isValidDbUser method returning boolean might be able to handle SQLExceptions as just return false; but a getNumProductsRegisteredInDB returning an int should almost certainly propagate an exception).
Don't listen to the (hordes) of people that will tell you that you should never catch multiple exceptions in one big general block. It's a perfectly reasonable way to do general error handling in some cases, which is why the ability to do so exists in the language.
There will be some exceptions that you can do something specific and useful about (i.e. recover from them in the catch block.) These are the kinds of exceptions that you want to catch individually, and as close to the place where they occur as possible.
But the majority of exceptions that you'll face in real life will be completely unexpected, unchecked exceptions. They are the result of programmer error (bugs), failed assertions, failing hardware, dropped network connections, etc.
You should design your software defensively, by designating specific "chokepoints" to handle these unpredictable exceptions with a minimum of disruption to the rest of the application. (Remember, in many cases, "handling" the exception often just means aborting the current operation and logging an error or otherwise telling the user that an unexpected error occurred.)
So for example, if your program saves a file to the disk, you could wrap the entire save operation in a try block to catch things that goes wrong during the save:
try {
// attempt to perform the save operation
doSave();
} catch (Throwable t) {
// tell the user that the save failed for unexpected reasons
// and log the error somewhere
informUser("save failed!");
log("save failed!", t);
} finally {
// last minute cleanup (happens whether save succeeded or failed)
...
}
Notice that we choose a nice chokepoint method here ( doSave() ) and then stop any unexpected errors from bubbling up any further than this point. The chokepoint represents a single, cancellable operation (a save). While that operation is obviously toast if you're getting an unexpected exception, the rest of the application will remain in a good state regardless of what happens on the other side of the chokepoint.
Also notice that this idiom does NOT stop you from handling some of your exceptions further down in doSave() somewhere. So if there are exceptions that might get thrown that you can recover from, or that you want to handle in a special way, go ahead an do so down in doSave(). But for everything else, you have your chokepoint.
You might even want to set up a general uncaught exception handler for your entire program in your main method:
public static void main(String [] args) {
try {
startApplication();
} catch (Throwable t) {
informUser("unexpected error! quitting application");
log("fatal application error", t);
}
But if you've set your other chokepoints up wisely, no exceptions will ever bubble up this far. If you want to make your general error handling complete, you can also create and assign an UncaughtExceptionHandler to important threads, including your main thread or the AWT thread if you are using Swing.
TL;DR; Don't believe the dogma that you should always catch exceptions as specifically as possible. There are times when you want to catch and handle a specific exception, and other times when you want to use chokepoints to catch and deal with "anything else that might go wrong".
I know two approaches to Exception handling, lets have a look at them.
Contract approach.
When a method does not do what it says it will do in the method header, it will throw an exception. Thus the method "promises" that it will do the operation, and if it fails for some reason, it will throw an exception.
Exceptional approach.
Only throw exceptions when something truly weird happens. You should not use exceptions when you can resolve the situation with normal control flow (If statements). You don't use Exceptions for control flow, as you might in the contract approach.
Lets use both approaches in different cases:
We have a Customer class that has a method called OrderProduct.
contract approach:
class Customer
{
public void OrderProduct(Product product)
{
if((m_credit - product.Price) < 0)
throw new NoCreditException("Not enough credit!");
// do stuff
}
}
exceptional approach:
class Customer
{
public bool OrderProduct(Product product)
{
if((m_credit - product.Price) < 0)
return false;
// do stuff
return true;
}
}
if !(customer.OrderProduct(product))
Console.WriteLine("Not enough credit!");
else
// go on with your life
Here I prefer the exceptional approach, as it is not truly Exceptional that a customer has no money assuming he did not win the lottery.
But here is a situation I err on the contract style.
Exceptional:
class CarController
{
// returns null if car creation failed.
public Car CreateCar(string model)
{
// something went wrong, wrong model
return null;
}
}
When I call a method called CreateCar, I damn wel expect a Car instance instead of some lousy null pointer, which can ravage my running code a dozen lines later. Thus I prefer contract to this one:
class CarController
{
public Car CreateCar(string model)
{
// something went wrong, wrong model
throw new CarModelNotKnownException("Model unkown");
return new Car();
}
}
Which do style do you use? What do you think is best general approach to Exceptions?
I favor what you call the "contract" approach. Returning nulls or other special values to indicate errors isn't necessary in a language that supports exceptions. I find it much easier to understand code when it doesn't have a bunch of "if (result == NULL)" or "if (result == -1)" clauses mixed in with what could be very simple, straightforward logic.
My usual approach is to use contract to handle any kind of error due to "client" invocation, that is, due to an external error (i.e ArgumentNullException).
Every error on the arguments is not handled. An exception is raised and the "client" is in charge of handling it. On the other hand, for internal errors always try to correct them (as if you can't get a database connection for some reason) and only if you can't handle it reraise the exception.
It's important to keep in mind that most unhandled exception at such level will not be able to be handled by the client anyway so they will just probably go up to the most general exception handler, so if such an exception occurs you are probably FUBAR anyway.
I believe that if you are building a class which will be used by an external program (or will be reused by other programs) then you should use the contract approach. A good example of this is an API of any kind.
If you are actually interested in exceptions and want to think about how to use them to construct robust systems, consider reading Making reliable distributed systems in the presence of software errors.
Both approaches are right. What that means is that a contract should be written in such a way as to specify for all cases that are not truly exceptional a behavior that does not require throwing an exception.
Note that some situations may or may not be exceptional based upon what the caller of the code is expecting. If the caller is expecting that a dictionary will contain a certain item, and absence of that item would indicate a severe problem, then failure to find the item is an exceptional condition and should cause an exception to be thrown. If, however, the caller doesn't really know if an item exists, and is equally prepared to handle its presence or its absence, then absence of the item would be an expected condition and should not cause an exception. The best way to handle such variations in caller expectation is to have a contract specify two methods: a DoSomething method and a TryDoSomething method, e.g.
TValue GetValue(TKey Key);
bool TryGetValue(TKey Key, ref TValue value);
Note that, while the standard 'try' pattern is as illustrated above, some alternatives may also be helpful if one is designing an interface which produces items:
// In case of failure, set ok false and return default<TValue>.
TValue TryGetResult(ref bool ok, TParam param);
// In case of failure, indicate particular problem in GetKeyErrorInfo
// and return default<TValue>.
TValue TryGetResult(ref GetKeyErrorInfo errorInfo, ref TParam param);
Note that using something like the normal TryGetResult pattern within an interface will make the interface invariant with respect to the result type; using one of the patterns above will allow the interface to be covariant with respect to the result type. Also, it will allow the result to be used in a 'var' declaration:
var myThingResult = myThing.TryGetSomeValue(ref ok, whatever);
if (ok) { do_whatever }
Not quite the standard approach, but in some cases the advantages may justify it.