Question

MethodA calls an MethodB which in turn calls MethodC.

There is NO exception handling in MethodB or MethodC. But there is exception handling in MethodA.

In MethodC an exception occurs.

Now, that exception is bubbling up to MethodA, which handles it appropriately.

What is wrong with this?

In my mind, at some point a caller will execute MethodB or MethodC, and when exceptions do occur in those methods, what will be gained from handling exceptions inside those methods, which essentially is just a try/catch/finally block instead of just let them bubble up to the callee?

The statement or consensus around exception handling is to throw when execution cannot continue due to just that - an exception. I get that. But why not catch the exception further up the chain instead of having try/catch blocks all the way down.

I understand it when you need to free up resources. That's a different matter entirely.

Was it helpful?

Solution

As a general principle, don't catch exceptions unless you know what to do with them. If MethodC throws an exception, but MethodB has no useful way to handle it, then it should allow the exception to propagate up to MethodA.

The only reasons why a method should have a catch and rethrow mechanism are:

  • You want to convert one exception to a different one that is more meaningful to the caller above.
  • You want to add extra information to the exception.
  • You need a catch clause to clean up resources that would be leaked without one.

Otherwise, catching exceptions at the wrong level tends to result in code that silently fails without providing any useful feedback to the calling code (and ultimately the user of the software). The alternative of catching an exception and then immediately rethrowing it is pointless.

OTHER TIPS

What is wrong with this ?

Absolutely nothing.

Now, that exception is bubbling up to MethodA, which handles it appropriately.

"handles it appropriately" is the important part. That's the crux of Structured Exception Handling.

If your code can do something "useful" with an Exception, go for it. If not, then let well alone.

. . . why not catch the exception further up the chain instead of having try/catch blocks all the way down.

That's exactly what you should be doing. If you're reading code that has handler/rethrowers "all the way down", then you're [probably] reading some pretty poor code.

Sadly, some Developers just see catch blocks as "boiler-plate" code that they throw in (no pun intended) to every method they write, often because they don't really "get" Exception Handling and think they have to add something so that Exceptions don't "escape" and kill their program.

Part of the difficulty here is that, most of the time, this problem won't even get noticed, because Exceptions aren't being thrown all the time but, when they are, the program is going to waste an awful lot of time and effort gradually unpicking the call stack to get up to somewhere that actually does something useful with the Exception.

You have to make a difference between Libraries and Applications.

Libraries can throw uncaught exceptions freely

When you design a library, at some point you have to think about what can go wrong. Parameters could be in the wrong range or null, external resources could be unavailable, etc.

Your library most often will not have a way to deal with them in a sensible manner. The only sensible solution is to throw an appropriate Exception and let the developer of the Application deal with it.

Applications should always at some point catch exceptions

When an Exception is caught, I like to categorize them as either Errors or Fatal Errors. A regular Error means that a single operation within my Application failed. For instance, an open document could not be saved, because the destination was not writable. The only sensible think for the Application to do is inform the user that the operation could not be completed successfully, give human-readable information in regards to the problem and then let the user decide what to do next.

A Fatal Error is an error the main Application logic cannot recover from. For instance, if the graphics device driver crashes in a video game, there is no way for the Application to "gracefully" inform the user. In this case, a log file should be written and, if possible, the user should be informed in some way or another.

Even in such a severe case, the Application should handle this Exception in a meaningful way. This might include writing a Log file, sending a Crash Report, etc. There is no reason for the Application not to respond to the Exception in some way.

What's wrong with the pattern you describe is that method A will have no way of distinguishing between three scenarios:

  1. Method B failed in an anticipated fashion.

  2. Method C failed in a fashion not anticipated by method B, but while method B was performing an operation that could be safely abandoned.

  3. Method C failed in a fashion not anticipated by method B, but while method B was performing an operation that placed things in a supposed-to-be-temporary incoherent state which B failed to clean up because of C's failure.

The only way method A will be able to distinguish those scenarios will be if the exception thrown from B includes information sufficient for that purpose, or if the stack unwinding for method B causes the object to be left in an explicitly invalidated state. Unfortunately, most exception frameworks make both patterns awkward, forcing programmers to make "lesser evil" design decisions.

Licensed under: CC-BY-SA with attribution
scroll top