See also ThrowDontCatch.
Don't catch exceptions when you don't want to. Just don't. Instead, let them trickle up the call tree until either you have a good solution or you hit the main function, in which case you can be sure that error information is correctly routed.
To a log file? To the browser? It is not your concern at the moment. You express that decision once in the system. Don't worry about it. Just let the exception pass upwards.
If you catch an exception, you have to do something with it. Your choices are:
1. Solve the underlying problem and retry. 2. Turn it into another kind of exception and pass it upwards. 3. Perform some kind of cleanup action and rethrow the exception (or a derivative). 4. Complain to some destination (message sink) and limp along. 5. Drop it on the floor, pull an answer out of your arse, and limp along.
The first three are responsible choices.
The last two are irresponsible. They deny the possibility that an assumption could change in the future. They prevent maintenance from finding the underlying cause of otherwise strange behaviour. Your software commits a sin of omission when it fails to report an unresolvable error condition to its superordinate.
The trouble is that so many beginning and journeyman programmers seem to like:
try { something; return true; } catch (Exception e} {e.printStackTrace(); return false; }In fact, I propose a simple static analytical test you can use for finding one class of BadCode in java: grep for printStackTrace. If you find it more than once in your system, you need to educate your developers.
Once is enough to get all your error reporting and logging needs met.
Now, no method that you write should ever throw "Exception". Use a meaningful exception wrapper class. Write code like:
class SomeParticularTypeOfFailure? extends Exception {}In sum, you should never bite off more exception handling than you can chew. -- IanKjos
Counterpoint: This seems to be a naive generalization. Consider an agent processing system. If there is a remote exception retrieving an agent to call #run on, why should the agent consumer do anything other than log the exception and continue? What about a thread pool or work queue - should all work stop because a task propagated an exception from its local run method? The LAST thing you should do in this case is propagate the exception to main. You should simply log it and continue.
Parry: But wait. An agent processing system would have a single centralized mechanism for dealing with unanticipated exceptions from agents, correct? See OnceAndOnlyOnce. The problem in this case comes when each agent has its own method for logging exceptions, and that's just the sort of BadCode you want to avoid.
Riposte: Since the agent processing system has been informed of the one true way to deal with ProblemChildren?, it is fully capable of "Fix the problem and retry (the next time around)". -- IanKjos
What about expected exceptions which are "unrepairable"? In VisualBasic, we have a collection class which lacks an Existing property so we don't know whether a particular key exists or not. The collection throws an error on every operation on non-existing keys. In some circumstances, it is OK that the key does not exist, so the exception should be ignored. Is this considered 'a fix and retry' or 'limping along'? -- ThomasEyde
If it's a normal expected condition that you might get the exception, and you have a good well thought out response to the situation, then I think it counts as fixing the problem and retrying the operation. The problem, in this case, was the mistaken guess that the collection had the key in question. The fix is to accept that the collection doesn't have this key, and continue with the algorithm given your new knowledge. This is still an algorithm-dependent choice; if your algorithm expects that key to exist, then you shouldn't trap the exception. You could write yourself a has_key() method that encapsulated this exception-check.
A problem arises when implementing an interface that doesn't declare a thrown exception. E.g. if I'm implementing java.lang.Runnable and I have code inside public void run() that throws an exception, I can't change the method signature and use a "throws" clause. I have to handle the exception within the run() method or within the code below. The propagation of exceptions stops as soon as this situation arises. -- GarethCronin
In Java, you can ALWAYS throw a RuntimeException or a derivative thereof. That's not always what you want, but it solves the interface constriction issue in the same way as what happens in the event of a null pointer dereference. If you're implementing Runnable, then you have an idea what happens in the event of a NullPointerException. The same sort of logic can handle "I'm runnable, but my legs are broken!".
I once wrote many empty 'catch' blocks. Once, I also spent many hours trying to figure out why I'd get a 'null pointer', 'not initialized', or 'just plain weird' error. Then I saw the light. :)
If I'm expecting the exception, and choose to do nothing, that's one thing.... write the empty block.
In any other case, if I'm about to write an empty block, upgrade the exception to RuntimeException or Error.
Benefits:
I was recently working with someone that had written an empty catch block. He assured me that there is no way on earth that the exception could possibly be thrown. So I suggested that instead of leaving it empty, he should do a System.exit (logging the impossible event first) ... he wasn't so sure anymore. ;) -- ChanningWalton
We created a Debug.assertImpossible(String message) method (which throws a runtime exception containing "Impossible happened : " and the message) to put into places which are "impossible", especially in the default: part of some switch statement. Well, impossible happened quite a few times during testing, fortunately none happened in the production system so far. -- OliverChung
In Microsoft Visual C++, a "catch (...)" clause will catch system exceptions like access violations, divide-by-zero, etc. In other words, you are catching an application crash. You almost never want to try to fix-and-retry or continue the program under these circumstances. It might make sense to try to log something, or to attempt some sort of orderly termination. If you do catch it, make sure you rethrow the exception so that the program can die the death it deserves.
The LetItFail? idiom of ErlangLanguage programming is DontCatchExceptions's big brother.