Wednesday, July 6, 2011

Excpetions - if you haven't caught on then you should try to

I am sure this has been said before but I came across an error that occurred yesterday.  I was told the code was working.  For the most part I could see that in the staging environment it was working just fine.  Sunday comes around.  My install day.  I check the staging environment.  I find that there is a null pointer exception.  The code crashed at a strange point.  With some deduction I realize where the error is coming from.  A method was called on an object that was clearly null, hence causing the exception.  The object that caused the exception was instantiated on the line before.  So no doubt there.  I the method called on the line before returns the object in question so I look at the method, which happened to be in a different class.  I see:

public SomeObject badMethod(InputObject obj){
  try {
       <code some of which that could cause an exception..
          including declaration of SomeObject 
          and return of the instantiated object>
  }
  catch (Exception e) {
     return null;
  }
}

Two big problems with this, possibly three.  The minor of all of these is that so much code is in the try block.  I am not sure if this is wrong, but at the same time it doesn't look right mainly from a maintenance point of view.  I had to delete the try and catch lines to find out which line of code require the exception handling, thanks to Eclipse that bit was simple.

I found out that the exception was actually a ParseException.

TIP #1: When using try catch blocks to catch exceptions, catch the specific exception.  Always be more explicit when you can.  Code is more understandable and you have the specific exception object available to you in the catch block.

The really big problem was how this was handled.  Theoretically I have no problem with returning null from a method.  However if you use a method that could return null that value must be handled.  Sometimes it is better if the method throws an exception instead.

TIP #2: If the method could return null you must test for it.  Otherwise you will end up with a nasty NullPointerException

In my case I ended up with an unhandled NullPointerException instead of a ParseException.  I had no further information about this as well.  This brings me to another point, at the very least you want to have the line

e.printStackTrace();

in the catch block.  At least then you can track the exception properly.  Better still use a logger, and add a little message of your own perhaps with some variable values printed so that you have an idea of what went wrong in your log or on your console. With most loggers you can add the the exception itself as an argument and the logger will handle outputting the relevant information from it.

TIP #3: Use a logger to print a sensible message from the catch block.

In this example the there was no real exception handling in the code.  The catch block just returns a null which is not handled in the calling code.  My solution in this case was to add a sensible logging line and throw the exception again.  This way the exception is passed up the stack.  The key here is that it forces the calling method to handle this exception.  In this case that works, I needed an extra try catch block, but the error will be handled better.  Now the parse exception will be passed up through the calling stack and the method will now handle this error correctly.

TIP #4: Handle the exception, its not enough just to print the stack trace or log the error.

Conclusion:
The tips I have presented here are very important when dealing with exceptions in Java.  It is too easy, especially in Eclipse which does so much for you, to leave the printStackTrace() in there and not do anything else.  But they must be handled.  Learn to use them problem and exceptions will be your friend.  Errors will be handled correctly and the code will run more smoothly and hopefully be a little more readable.

Happy coding.

No comments:

Post a Comment