views:

149

answers:

6

Usually I do all what I can inside a class, in every method (try and catch). Am I doing it wrong? Recently I heard better way is handle error in program body...

What is good habit?

+7  A: 

If you can handle an exception, then do so. If you can't, then let the exception bubble up to someone that can!

Jeff Foster
+4  A: 

Some general thoughts:

  1. Throw exceptions for exceptional error conditions only.

  2. Fail fast.

  3. Since you are throwing exceptions for exceptional error conditions only, the assumption is that you cannot fix it within the class, so the exception should bubble up the call stack. Whether you handle it in the immediate class above it, or handle it in a catchall catch, is up to you.

Robert Harvey
I'd suggest "throw exceptions for **error** conditions only." Error conditions should be exceptional (not main program flow), but I like the implied perspective. For instance, if you're doing error handling with error codes, switch to exceptions.
TrueWill
Yes, that is what I meant. Fixed my post.
Robert Harvey
A: 

You should be handling exceptions whenever you can make a productive reaction. If it has to bubble up higher, then let it.

I also repackage exceptions as soon as they can be thrown by some layer lower than my code. A good example of the benefit can be seen in doing SQL calls in Java. Everything throws an SQLException, which isn't helpful if I have a method that can trigger multiple exception, but can't handle them. By repackaging, I can differentiate and react differently between a failed connection and problem constructing a prepared statement.

unholysampler
A: 

I believe that the best approach may be a mixed approach.

Perform error handling in the class for problems pertaining to the class. For example, if the property-setters do validation, those errors are detected and thrown from the class.

At the web page or form level, you can handle all errors in one method. For an ASP.Net web app, for example, you could use the Page_Error method to catch all exceptions that reach the page. Then, you display the error message text thrown by the class property setter.

Alternately, you can include an errorMessage string return value in every method signature. The calling page/form checks for the contents of the errorMessage, and decides what to do based on the context. This requires more coding than the above approach.

Sometimes, the class does not know whether the event is actually an error. For example, if a class method selects a record from the database and returns its data, the class doesn't know whether this is an error. If the page/form calling the class method is a search page, then getting no records returned is not an error, it's "record not found", and that information is displayed.

DOK
+2  A: 

In general, exception handling should be done in the business/controller logic/layer whenever you need to "translate" the exception to the enduser. Thus not in for example data layer, model layer, view layer and utility classes.

Catching runtime exceptions such as null pointers, arithmethic errors, array index out of bounds etc should in general not be done. They in general just indicate progamming errors. You should just write the code accordingly so that they should never occur (e.g. if (x != null) { x.doStuff() }).

BalusC
If you are writing a multi-tier application, this is true.
Robert Harvey
+2  A: 

How you interact with exceptions depends on where your code lives in the application strata. In general, error reporting is a matter of UI, and that is usually best left to the application, the outermost layer of code.

Low-level code and mid-level business logic code is often shared between different applications. Since different applications will have different policies toward how much and which errors should be reported to the user, low-level and mid-level code should avoid handling exceptions for the purpose of error reporting. Let the application do that.

There are plenty of legitimate reasons for trapping an exception in low-level and mid-level code, particularly to try an alternate path if the primary path fails, or to convert a low-level exception into an exception more specific to the current operation. Just be careful not to go overboard, make your exception traps as specific as possible (don't overgeneralize or you'll trap things you're not prepared to handle), and be extremely critical of squelching an exception entirely in low and mid level code.

The general philosophy for low and mid level code should be: If the action that the caller requested fails, the let the caller see the consequences - the exception.

Your low and mid level code will often naturally fall into two camps: "hard" functions that either perform the requested action or throw an exception if that can't be done, and "soft" functions that are more of a convenience for experimental probing. If an operation will probably fail most of the time, like "FileExists()", then it's probably a poor use of exceptions to throw an exception on failure and require the caller to wrap all calls to this function in an exception handler. That would be creating more work for the caller. In this use case, FileExists() should be a "soft" function that returns true/false instead of throwing. A "hard" version of this might be called "RequireFile()", which throws if the file is not found.

As a naming pattern, you often see "Try" as a prefix to soft functions. So, GetData() would be the hard function which throws if it can't do the work, and TryGetData() would be the soft function that returns a boolean instead of throwing. Depending on usage, it's common to see both functions in a class or library.

These pairs are often implemented as one calling the other - GetData() calls TryGetData() and throws if TryGetData() returns false, or TryGetData() calls GetData() inside a try..catch block. Which pattern to use depends on the complexity of the work being done by the function. If the failure case is easily detected by boolean logic (low risk of exceptions), then TryGetData would be the primary implementation. If the failure case fails by exception, then GetData would be the primary implementation.

"Hard" functions let the caller take full advantage of exceptions to streamline program logic - if this call succeeds, then I can move on to the next step using the call results. If this call fails, it will throw an exception and the next step won't execute. "Hard" functions let you blast through a sequence of operations with the proper assumption that each operation returns legitimate results, because if an operation can't return legitimate results it will throw and blow us out of this operation sequence. This lets you concentrate primary path program logic without the clutter of fire-brigade error handling - analyzing function error codes on every call and deciding what to do with them.

dthorpe