Thursday, August 10, 2006

Empty String

How many times have you coded a check for String being null or empty? Countless times, right? I have. We use some ready-to-use classes from open source frameworks or we write our own StringUtils class. More or less they all implement the same thing and it always looks similar to the following code snippet:

String s = ...
if (s == null || s.equals(""))...

or similar to the following, which trims leading and ending whitespaces

String s = ...
if (s == null || s.trim().equals(""))...

Of course you could also do this:

"".equals(s)

which is a case when you do not care if String s is null and you don't have to worry about NPE as if won't happen ("" is never null, whereas s could be). But that's another story.

I have had "extra" warnings turned on in my IDE for couple of days. But today my IDE suprised me when it highlighted

[1] s.equals("")

and suggested that I could optimize it by making it to

[2] s.length() == 0

And guess what?! The IDE was right! I looked at the suggested code briefly, gave it a bit of thought and agreed that it would probably be faster. Method [1] creates a new instance of the String (an empty String, yes I know that all instances of "" would be caught during compilation and optimized and that they all would refer to the same instance). Just to be on the safe side I looked at the source of the String class.

And here is what I found. The length() method returns and integer primitive, which is not calculated with each method call to length(). It is rather a member variable (or constant, as Strings are invariants) of String class that is calculated when new String instance is created. So this method would be super fast.

536   public int length()
537 {
538 return count;
539 }

On the other side, there is the equals() method, which is fast as well, but not as fast as length method. It has to do a check for class, class casting and comparison of count members (that's what length method returns).

684   public boolean equals(Object anObject)
685 {
686 if (! (anObject instanceof String))
687 return false;
688 String str2 = (String) anObject;
689 if (count != str2.count)
690 return false;
691 if (value == str2.value && offset == str2.offset)
692 return true;
693 int i = count;
694 int x = offset;
695 int y = str2.offset;
696 while (--i >= 0)
697 if (value[x++] != str2.value[y++])
698 return false;
699 return true;
700 }

And remember the few important points when it comes to Strings:

  • Do not compare Strings with == operator. Unless you want to compare the object references. Use equals() method.

  • Do not construct new instances like new String("abc"). Simple "abc" will do, unless you really mean that you need a new instance of String with same value. Read more about How useful is String(String) constructor

  • Do not concatenate Strings in loops using + operator. It's faster to use StringBuffer (or StringBuilder, which is in Tiger and is not synchronized) append() and then toString() methods instead. The plus (+) operator constructs new String object each time.

13 comments:

Anonymous said...

Thanks for the explanation on the empty comparison ! Exactly what i was looking for :)

Anonymous said...

Thanks for the discription regarding the empty string .It was Very useful .

Kamal said...

Thanks for sharing.

Jay Bose said...

Wow. I thought you were kidding when ya thanked that guy for quoting your entire article.

Unknown said...

Well, I did not like the way he posted it (he did not ask for permission), but fairly enough he placed a link to my original post at the end.

Besides, I put some more links pointing to my blog in the comment I left on his page, which resulted in more traffic being driven my way anyway.

The comment you left here just proves it :-)

Joni said...

But wouldn't length() return a NullPointerException if the string turns out to be null?

Unknown said...

Nothing stops you from doing this

if (s == null || s.length() == 0) ...

Anonymous said...

how abt using the StringUtils class and using the isBlank method which takes care of null,empty and whitespace?
Which usage is better?

Unknown said...

Sure! Libraries are all about code re-usability. See my How much code can be re-used? post for more information.

Anonymous said...
This comment has been removed by a blog administrator.
Adam Monsen said...

Maybe the VM could/should optimize s.equals("") to s.length() == 0.

Addy said...

Well,it will throw null pointer exception...

Anonymous said...

String class has a special method
isEmpty() that is to be used for empty comparison. It is way better than s.length() == 0 because:
- Less noisy
- Explicitly tells what you want
- Delegates efficient implementation to the class String that knows better how to implement it efficiently

BTW this is the implementation:

public boolean isEmpty() {
return count == 0;
}

Writing s.length == 0 is efficient but not a good style.


Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.