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 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 as well, therefore it is important to know how the JVM can sometimes trick you.

The String comparison problem

Consider this piece of 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 snippet above creates (apparently) two different String objects with the same value and then compares them with the == operator. Therefore we would expect the comparison with == to fail.
However by running it we notice that it works like a charm

Comparing "test01" and "test01"
Matches

Why is that? This is the tricky part. You may now be thinking that your code is working fine even if you used the == operator. Actually many developers just move on with their life and never think of this again, until random scary bugs start to appear. What’s really happening is that your code is not working, but for a fluke of destiny it looks like it is.

Explaining the unexplainable

Interning is at work here, just like for Integer and Long in the previous post. In Java all literal strings are automatically interned. This means that both a and b are pointing to the same instance of String that was created and when a was created with a literal value. When a and b are compared with a == b everything works because they point to the same String instance.


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

This code 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, but when we append “01” to b a brand new String object is created because of String immutability. The value of the new String instance is still “test01”, but the instance is different.

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

Conclusion

Not much to add. Do not be fooled, always use the equals() method to compare objects values in Java.

Unique opportunity! Help a fellow grow his blog!

Hi there! If you’ve read this far maybe you think this was useful, or fun, or I don’t know what but for some reason You Got Here! Great! Please consider sharing this post with your network, I am trying to get The Code Butchery to grow so I can provide more content like this, will you help me in my journey? Thank you!

Share this

Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.