How not to compare Strings in Java

In my previous post I wrote about how not to compare Integer and Long objects in Java in order to avoid undefined behaviours in your code caused by the Java interning mechanism. If not well understood interning can lead to catastrophic failures. You may think that your code is working fine while in fact it is not working at all.

Interning is used for String objects too so it’s important to know how the Java virtual machine can fool you. Let’s have a look at this code:

public static void main(String[] args) {
		
  String a = "test01";
  String b = "test01";
		
  System.out.println("Comparing \"" + a + "\" and " + "\"" + b + "\"");

  if (a == b) System.out.println("Matches");
  else System.out.println("Doesn't match");
		
}

Every Java developer knows that String objects cannot be compared with the == operator, because it only compares object instances and not objects values, the equals() method must be used instead. The code above creates two different String objects with the same value and then compares them with the == operator, thus the comparison should fail even if the values are the same.
However if you run it you’ll notice that it works perfectly, the output is:

Comparing "test01" and "test01"
Matches

This is the tricky part. You may now be fooled into believing that your code works fine while in fact it does not.

Interning is at work here, just like for Integers and Longs in the previous post. In Java all literal strings and string-valued constant expressions are interned. This means that both a and b in the code above are referencing the same instance of String that was created and interned when a was created with a literal value.

String a = "test01";
/** A String instance with value "test01" is now interned */

The code above will stop working as soon as it gets a little more complex:

public static void main(String[] args) {
		
  String a = "test01";
  String b = "test";
		
  b += "01";
		
  System.out.println("Comparing \"" + a + "\" and " + "\"" + b + "\"");
  if (a == b) System.out.println("Matches");
  else System.out.println("Doesn't match");
		
}

This time two String instances with values “test01” and “test” are interned, and when we append “01” to b a completely new String object is created (because of objects immutability) with value “test01” which will not refer to the interned one with the same value.
The output now is:

Comparing "test01" and "test01"
Doesn't match

Always use the equals() method to compare objects values in Java.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: