e.printStackTrace() is not for you
While reading through another team’s Java codebase recently, I came across a disturbing proclivity for code like this
public SomeType aMethod() { SomeType result = null; try { anObject.thatDoesSomething(); result = anObject.getSomethingElse(); } catch (SomeTypeOfException e) { e.printStackTrace(); // or, sometimes, log.error(e); } return result; }
This is called swallowing the exception. The only way to know that an exception occurred is to have access to the stderr stream of the process (or, if logging was used, the logs). Since the software product referred to above runs inside an application server, clients never get to see this information. The method just returns null. Sometimes it’s obvious that null indicates a problem. Other times, however, the client may wrongly interpret null as absence of information.
This brings me to what I think should be a rule for Java code: almost always, printStackTrace() is not for us to use. Its only utility is for toy programs and logging libraries. When presented with exceptions that your code cannot handle itself, you should rethrow those exceptions up the call stack, so that the server container can report problems to any client and to the application logs.
Sometimes you have to wrap exceptions in another type of exception (e.g. a ServletException) or a custom runtime exception (we usually create a class SystemException for this), because the callbacks your server gives you do not declare that they throw the right exception type. This is one of the reasons I like using Spring MVC; the controller callbacks all declare that they throw Exception (although I’m sure most other modern Java web frameworks share this property these days).
So, remember (if you didn’t already know, which most of you probably do): if you see e.printStackTrace() in your code, it likely means your code has a problem you need to fix. Even throwing new RuntimeException(e) is better than swallowing the exception.
Update: Reading this later, I realized I left out an important point. The above assumes you actually need the try/catch block. If SomeTypeOfException were an unchecked (i.e. runtime) exception, you could just let it bubble up the call stack. If it’s a checked exception, in order to let it bubble up, you have to declare the exception in the method signature. This is unadvisable if the exception makes no sense for the method (e.g. declaring that an Employee’s getPhoneNumber() method throws SQLException). In this case it’s preferable either to wrap the exception in a checked exception that makes sense in the method signature or in an unchecked exception that does not need to be declared.