It depends on whether you can deal with the exceptions that can be raised at this point or not.
If you can handle the exceptions locally you should, and it is better to handle the error as close to where it is raised as possible.
If you can't handle them locally then just having a try / finally
block is perfectly reasonable - assuming there's some code you need to execute regardless of whether the method succeeded or not. For example (from Neil's comment), opening a stream and then passing that stream to an inner method to be loaded is an excellent example of when you'd need try { } finally { }
, using the finally clause to ensure that the stream is closed regardless of the success or failure of the read.
However, you will still need an exception handler somewhere in your code - unless you want your application to crash completely of course. It depends on the architecture of your application exactly where that handler is.
First of all, I would disagree with this statement:
Favour exceptions over error codes
This is not always the case: for example, take a look at Objective-C (with the Foundation framework). There the NSError is the preferred way to handle errors, despite the existence of what a Java developer would call true exceptions: @try, @catch, @throw, NSException class, etc.
However it is true that many interfaces leak their abstractions with the exceptions thrown. It is my belief that this is not the fault of the "exception"-style of error propagating/handling. In general I believe the best advice about error handling is this:
Deal with the error/exception at the lowest possible level, period
I think if one sticks to that rule of thumb, the amount of "leakage" from abstractions can be very limited and contained.
On whether exceptions thrown by a method should be part of its declaration, I believe they should: they are part of the contract defined by this interface: This method does A, or fails with B or C.
For example, if a class is an XML Parser, a part of its design should be to indicate that the XML file provided is just plain wrong. In Java, you normally do so by declaring the exceptions you expect to encounter and adding them to the throws
part of the declaration of the method. On the other hand, if one of the parsing algorithms failed, there's no reason to pass that exception above unhandled.
It all boils down to one thing:
Good interface design.
If you design your interface well enough, no amount of exceptions should haunt you.
Otherwise, it's not just exceptions that would bother you.
Also, I think the creators of Java had very strong security reasons to include exceptions to a method declaration/definition.
One last thing: Some languages, Eiffel for example, have other mechanisms for error handling and simply do not include throwing capabilities. There, an 'exception' of sort is automatically raised when a postcondition for a routine is not satisfied.
Best Answer
Imagine code with thousands files using a bunch of libraries. Imagine all of them are coded like this.
Imagine, for example, an update of your server causes one configuration file disappear; and now all you have is a stack trace is a null pointer exception when you try using that class: how would you resolve that? It could take hours, where at least just logging the raw stack trace of the file not found [file path] may enable you to resolve momentarily.
Or even worse: a failure in one off the libraries you use after an update that makes your code crash later on. How can you track this back to the library ?
Even without robust error handling just doing
or
may save you hours of time.
But there are some cases where you might really want to ignore the exception and return null like this (or do nothing). Especially if you integrate with some badly designed legacy code and this exception is expected as a normal case.
In fact when doing this you should just wonder if you really are ignoring the exception or "properly handling" for your needs. If returning null is "properly handling" your exception in that given case, then do it. And add a comment why this is the proper thing to do.
Best practices are things to follow in most of cases, maybe 80%, maybe 99%, but you'll always find one edge case where they don't apply. In that case, leave a comment why you're not following the practice for the others (or even yourself) who will read your code months later.