The Lurker
Don't initialise it yet
Today's lesson is inspired by generated code produced by an EJB container which shall remain nameless:
PersistenceManager pm = null; try { pm = findPersistenceManager(); pm.fetch(something); } catch (PersistenceException e) { throw new ObjectNotFoundException(message); } finally { pm.close(); }
Needless to say, findPersistenceManager()
throws PersistenceException if you have not configured persistence management correctly, leaving pm
set to null. So that finally block triggers a completely unhelpful NullPointerException.
Also needless to say, this makes it difficult to identify configuration errors.
The moral of the story?
- Don't try to call close() on something you may or may not have acquired.
- Don't initialize pm until you've successfully located the PersistenceManager; that way, the compiler can tell you if you try to do #1.
- It won't kill you to nest a try block inside another try block. The correct thing to do here would have been something more like:
PersistenceManager pm; try { pm = findPersistenceManager(); try { pm.fetch(something); } finally { pm.close(); } } catch (PersistenceException e) { throw new ObjectNotFoundException(message); }
Interestingly, Python supports try-finally
and try-except
(except
being equivalent to Java's catch
) but not try-except-finally
blocks, which results in code similar to the above for ensuring that a resource is released correctly.
Personally, I prefer that approach. It would be OK to test (pm != null)
before calling close()
, but I prefer the above construct, even though it is a bit noisier, because it allows the compiler to help you catch this type of error.
All timestamps are Melbourne time.