The abuse and over-use of toString()
This one is sneaky.. most programmers when writing debug code tend to call the toString() method on an object to retrieve human-readable information and present it to the user in some shape or form (logs, system out, etc). That's good programming.. when debugging a problem we want to be able to read and view all information possible..
Here is the sneaky part.. you should never *never* call toString() on a Java object unless you're pretty damn sure that object will never be null. Why? It's simple.. calling toString() on a null object will generate our good old friend -- the null pointer exception. (What? Java has no pointers! -- wrong!). This is a huge problem.. Think about it.. where do we usually put most of our debugging code? That's right.. error handling.. Something like this, perhaps:
try
{
myObject = doSomething();
}
catch (HorribleException e)
{
String msg = "Dude, we got us a problem: " + e.getMessage();
msg += "The object looks like this" + myObject.toString();
// do logging and stuff..
//
}
If myObject happens to be null, which may very well be the case considering we have an exception while trying to create, modify or reference it it will throw a null pointer exception at which point this becomes a debugging nightmare as the original exception is now lost. Maybe not a huge nightmare in a development environment.. but try to debug issues with code like this in a production environment where all you have to go on is logs and system output. Right.. nightmare.
What should you do instead? Forget toString()! There is a better way of doing it and that's String.valueOf(object) which is implicitly called on calls that convert objects to strings. String.valueOf(object) internally calls toString() on the object -- but it checks for nulls! This is the behaviour you want in your debugging code.. if the object is null you do not want an exception.. just a "null" ought to suffice and the toString() output otherwise..
try
{
myObject = doSomething();
}
catch (HorribleException e)
{
String msg = "Dude, we got us a problem: " + e.getMessage();
msg += "The object looks like this" + myObject;
// do logging and stuff..
//
}
Will generate exactly the same output as the first example when object is fine.. but only the string "null" when object is null. Safer and even less typing! The scary part is how many experienced programmers have no clue about this little gotcha.. go spread the word. Thanks.
Comments
Wouldn't this be even better? :-)
...
String msg = "Dude, we got us a problem: " + e.getMessage();
try {
msg += "The object looks like this" + myObject.toString();
} catch ( Exception e ) { }
...
Posted by: Steve Friedl | June 21, 2003 06:45 PM
Steve..dude.. we've got us a problem :)
Posted by: kasia | June 21, 2003 06:57 PM
Hmmm... I still haven't learned Java.. does that make me the exception? ;-) :-D
Posted by: Starfish | June 22, 2003 06:23 AM
Thanks Kasia, for reminding me of something I figured out (and forgot) quite some time ago. Such reminders are truly valuable.
Posted by: Lance | June 22, 2003 10:04 AM
Kasia,
Sorry this is a little off topic, it's got to do with searching jar files, not null objects. :)
I am also a java developer, and just wrote an article for uptime about searching tar files. I based it on some scripts that I use to search jar files at work. You can just replace the 'tar' sections with 'jar' and some small changes in the scripts, and you can search jar files in a directory, or recursively, or whatever. It's really handy for searching jar files for contents.
the article, and site and all is all free, of course. I thought you may find it helpful, and I'm sure several of your readers may, also. :)
http://www.steidler.net/uptime/archives/000381.html#000381
Take care-
-Frank Merenda
p.s. the worse is when someone does one of THESE nubmers in a try/catch:
String msg = "You have a problem " + myObject.getSomething().getSomeValueFromThing();
There's always a null in there somewhere.... doh!
Posted by: Frank Merenda | June 23, 2003 05:15 AM
PMD - http://pmd.sf.net/ - can catch various problems with Strings, including:
- called "new String("foo");", which creates an unneeded object
- using the same String literal many times in the same class, which is usually a sign that it needs to be refactored to a constant
- calling toString on a String, which is ridiculous
Yours,
Tom
Posted by: Tom Copeland | June 23, 2003 12:08 PM
Or just use String.valueOf(object) which does a null-check internally.
Of course String concatenation calls this method automatically so if that's the context in which you need the String-representation of the object, a "string"+object will work just fine.
Either way, you're absolutely right about not calling .toString() on the object.
Similarly, developers should never write str.equals("literal_value"), but instead always use "literal_value".equals(str) as it will return false instead of throwing a NullPointerException in case str is null.
Posted by: Luke Hutteman | June 25, 2003 12:59 PM
This post is idiotic and overimportant. You shouldn't be calling ANY METHOD on an object unless you know that object isn't null, or you use this wonderful construct called the IF statement.
And, what's wrong with:
System.err.println("Object is: " + (object == null ? "null" : object.toString());
Or
System.err.println("Object is: " + object);
I can't believe what passes for a blog posting these days. In the next installment, be sure to compile your classes before trying to run your program!
Posted by: Dave | July 14, 2003 10:47 AM
So Dave, which year CS student are you now? And learn to read your "what's wrong with.." is what I said in this entry..
Psst, it's a blog, nobody makes you read it, go smoke something.
Posted by: kasia | July 14, 2003 04:22 PM