Adam Heath wrote:
Adrian Crum wrote:
Adam Heath wrote:
Adrian Crum wrote:
I remember you complaining a while back about developers who wrap
exceptions - because it makes code harder to debug. (I agree with that
view, btw.) Has that view changed?
try {
} catch (FooException e) {
    e.printStackTrace(); // Or Debug.logError(e)
    throw new BarException(e.getMessage());
}

That's what I complained about.  Utility code should *never* print(or
log) an exception.  It should always throw it to the calling code, and
let it decide.  Of course, then you have to figure out how much is
actually utility, and how much is higher-level.
Oh. Thanks for the clarification.

Why not add a throws clause to the enclosing FreemarkerWorker method?
Because that exposes the inner workings of the method in question.
Huh?

Using your example above, the calling code could make a decision based
on the exception thrown. For example, if FooException is thrown, try an
alternate method. But that decision can't be made, because FooException
is never thrown.

This is especially bad in some OFBiz classes where EVERY class method
throws the same home-grown exception. There is no way for calling code
to know what to do when an error is encountered.

Let's say that you have an existing method, that currently throws
GeneralException.  Then, later on, you add a feature to let it cache
it's results to disk.  This means you end up using java.io.* classes,
which suddenly start throwing IOException.  Now, should you change the
abi, adding a throws IOException to the method, or should you do an
initCause thing?  Remember, if you add a new throws, it will break all
source that is compiled against the new version.

If you go the new throws route, then all other methods on the stack
need to be alter as well, each in turn adding a new throws clause.
That very quickly becomes a maintenance nightmare.

However, let's say you decide it is worth it, and change all the
methods in the stack to have new catch blocks, or new throws.  Time
goes by, and you change this method to now try to do a network
connection to some other cache server, to try and load data.  Now it
has to throw a SocketException.  So you go thru the same round of code
changes.

If, instead, you had chosen to have a single per-api exception as the
only throws, then you wouldn't have to modify code all the time,
whenever you add new features.  Most call points wouldn't care about
why something failed(they wouldn't look at the initCause), they'd just
pass the exception up the stack.

That's a good example. It seems we made a case for the two approaches.

-Adrian

Reply via email to