views:

335

answers:

6

This is more a general purpose programming question than language specific. I've seen several appraoches to try and catches.

One is you do whatever preprocessing on data you need, call a function with the appropriate arguments and wrap it into a try/catch block.

The other is to simply call a function pass the data and rely on try catches within the function, with the function returning a true/false flag if errors occured.

Third is a combination with a try catch outside the function and inside. However if the functions try catch catches something, it throws out another exception for the try catch block outside the function to catch.

Any thoughts on the pros/cons of these methods for error control or if there is an accepted standard? My googling ninja skills have failed me on finding accurate data on this.

+2  A: 

Every "module" in an application is responsible for handling its own input parameters. Normally, you should find issues as soon as possible and not hand garbage to another part of the application and rely on them to be correct. There are exceptions though. Sometimes validating an input parameter basically needs reimplementing what the callee is supposed to do (e.g. parsing an integer) in the caller. In this case, it's usually appropriate to try the operation and see if it works or not. Moreover, there are some operations that you can't predict their success without doing them. For example, you can't reliably check if you can write to a file before writing to it: another process might immediately lock the file after your check.

Mehrdad Afshari
This doesn't seem to answer the question. It seems more like a review of ways exceptions can arise.
S.Lott
@S.Lott: I understood the question as if the OP wanted to know whether he should rely on another module to handle errors and return boolean success/failure values or let it throw exceptions and catch them higher in the call stack... Maybe I misunderstood it. It's quite long, and I guess it addresses a part of it, at least.
Mehrdad Afshari
A: 

I generally consider if as the caller of the method I can use an exception in any way (like, to recover from it by taking a different approach) or if it makes no difference and just went wrong if the exception occurs. So in the former case I'll declare the method to throw the exception while in the latter I'll catch it inside of the method and don't bother the caller with it.

Fabian Steeg
+4  A: 

In general, an exception should only be caught if it can actually be handled.

It makes no sense to catch an exception for no purpose other than to log it. The exception is that exceptions should be caught at the "top level" so that it can be logged. All other code should allow exceptions to propagate to the code that will log them.

John Saunders
+1: And, an exception can only be handled when a function contains alternative strategies for getting something done.
S.Lott
I think that catching an exception to produce usefull logging, with more context than the initial throw, can be usefull at times. After that, rethrow it if you can't handle the exception.
extraneon
"with more information" is the key. Just logging, with no additional information, should wait to the higher level.
John Saunders
A: 

The only question on catching exceptions is "are there multiple strategies for getting something done?"

Some functions can meaningfully catch certain exceptions and try alternative strategies in the event of those known exceptions.

All other exceptions will be thrown.

If there are not any alternative strategies, the exception will be simply thrown.

Rarely do you want a function to catch (and silence) exceptions. An exception means that something is wrong. The application -- as a whole -- should be aware of unhandled exceptions. It should at least log them, and perhaps do even more: shut down or perhaps restart.

S.Lott
+1  A: 

I think the best way to think about this is in terms of program state. You don't want a failed operation to damage program state. This paper describes the concept of "Exception Safety".

In general, you first need to decide what level of exception safety a function needs to guarantee. The levels are

  • Basic Guarnantee
  • Strong Guarantee
  • NoThrow Guarantee

The basic Guarantee simply means that in the face of an exception or other error, no resources are leaked, the strong guarantee says that the program state is rolled back to before the exception, and nothrow methods never throw exceptions.

I personally use exceptions when an unexpected, runtime failure occurs. Unexpected means to me that such a failure should not occur in the normal course of operations. Runtime means that the error is due to the state of some external component outside of my control, as opposed to due to logic errors on my part. I use ASSERT()'s to catch logic errors, and I use boolean return values for expected errors.

Why? ASSERT isn't compiled into release code, so I don't burden my users with error checking for my own failures. That's what unit tests and ASSERTS are for. Booleans because throwing an exception can give the wrong message. Exceptions can be expensive, too. If I throw exceptions in the normal course of application execution, then I can't use the MS Visual Studio debugger's excellent "Catch on thrown" exception feature, where I can have the debugger break a program at the point that any exception is thrown, rather than the default of only stopping at unhandled (crashing) exceptions.

To see a C++ technique for the basic Guarantee, google "RAII" (Resource Acquisition is Initialiation). It's a technique where you wrap a resource in an object whose constructor allocates the resource and whos destructor frees the resource. Since C++ exceptions unwind the stack, it guarantees that resources are freed in the face of exceptions. You can use this technique to roll back program state in the face of an exception. Just add a "Commit" method to an object, and if an object isn't committed before it is destroyed, run the "Rollback" operation that restores program state in the destructor.

David Gladfelter
What's a NoThrow Guarantee? Is this a C++ thing? In Java and Python there are numerous errors that you cannot (and should) not attempt to catch.
S.Lott
NoThrow is an absoultely necessary guarantee for the rest of the guarantees to be possible. Destructors and deinitializers (such as C's 'Free()') need to be NoThrow, meaning they'll never throw an exception. RollBack() functions should never throw, too. If you can't clean up program state without generating new exceptions, it means that you can't guarantee that program state won't be damaged. There are three ways of creating NoThrow operations. Compose them of only nothrow operations: logically guarantee that they can't throw, or put a try-catch that swallows the exceptions.
David Gladfelter
That said, there are three exceptions I'm aware of that you simply can't prevent all of the time. They are ThreadAbort exceptions (that's what they're called in .NET languages, there may be other equivalents in other languages), Out of Memory Exceptions, and Stack Overflow exceptions. All 3 are violations of the abstract concept of a program with limitless time, memory, and call recursion available to it. There's not much you can do about any of them. Fortunately, you can usually design a program not to get hit by those in the vast majority of cases.
David Gladfelter
+1  A: 

There are no real hard and fast rules around exception handling that I have encountered, however I have a number of general rules of thumb that I like to apply.

Even if some exceptions are handled at the lower layer of your system make sure there is a catch all exception handler at the entry point of your system (e.g. When you implement a new Thread (i.e. Runnable), Servlet, MessasgeDrivenBean, server socket etc). This is often the best place to make the final decision as how your system should continue (log and retry, exit with error, roll back transaction)

Never throw an execption within a finally block, you will lose the original exception and mask the real problem with an unimportant error.

Apart from that it depends on the function that you are implementing. Are you in a loop, should the rest of the items be retried or the whole list aborted?

If you rethrow an exception avoid logging as it will just add noise to your logs.

Michael Barker