Showing posts with label string. Show all posts
Showing posts with label string. Show all posts

Sunday, April 22, 2007

People still don't get String comparison

How many times we have seen String comparison done using == or != operators?! Yet, people still get it wrong.

I have seen some blog posts recently where the authors had a good intention to show a case where hard-coding values went wrong. Unfortunately, they fell into the common mistake of comparison of String references.

So, if you really need to compare two String using == or != make sure you call String.intern() method before making comparison. Otherwise, always prefer String.equals(String) for String comparison.

Tuesday, February 27, 2007

toString() and primitive values

How can one convert a primitive value such as integer or boolean to String object?

Well, there are many ways. There is one way that I have seen so many times:

String strValue = new Integer(intValue).toString();

or

String strValue = new Boolean(booleanValue).toString();

Similarly new instance can be created and the toString() method invoked on classes such as Integer, Long, Float, Double, Byte, Short and Boolean.

The problem is that a boxed primitive is allocated just to call toString() method on it. Each time this is executed, a new instance, new object is created. However, object creation is not necessary and can be avoided. Creating object just for one method call is highly inefficient as the object can be garbage collected on the consecutive line.

The solution

It is more efficient to use the static form of toString() method, which takes the primitive value as a parameter.

String strValue = Integer.toString(intValue);

or

String strValue = Boolean.toString(booleanValue);

Side note

...and please don't do the following

Integer number = ...
String strValue = Integer.toString(number.intValue());

If you already have an instance of integer wrapper class, simply call

String strValue = number.toString();

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.

Tuesday, March 14, 2006

How useful is String(String) constructor?

Good architectural design is essential. We can not expect junior programmers to know all APIs well. With good design good programming practices can be enforced and unintentional mistakes avoided. Architect’s and designer’s responsibility is to create a framework of interfaces, abstract classes, utility classes that other developers will use or implement.

Recently I came across this line

String value = new String(“some text”);

I have not seen String(String) constructor for a long while. Have you seen it recently? Probably not. And there is a good reason for it. For 99.9% of cases you won’t need it at all. It only serves as a copy constructor that takes a String as an argument and creates a new instance that represents the same string of characters. Further more first string created (“some text”) is ready for garbage collection on the very next line. It would only be useful if you were to compare the two strings as

someString == someOtherString

Generally, when I see such comparison it is a programming bug. In most of the cases the equals() method is used for String comparison.

someString.equals(someOtherString)

But that is another story. Anyway, back to String(String) constructor. Having this constructor may lead to unintentional object instance creation. When you create a String by putting anything between double quotes you already have an instance. There is no need to call new String(String). The following line will perfectly do the job.

String value = "some text";

I understand that the designers’ intention was to have a String copy constructor, but in this case, I do not believe, it was a wise step. A factory method would have been better. It could be called createNewInstance(String) or copy(String).

Good design is essential. But good design is not bullet proof. We still need to know the APIs, frameworks and things such as immutability of String objects.


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