Comparing Strings in Java

A common mistake by new Java programers is usingĀ == for comparing Strings. Often the results are correct when using the == comparison with Strings.

String s1 = "my string";
String s2 = "my string";

if ( s1 == s2) {
	// this comparison evaluates to true
	System.out.println("Why not use =='s ?");
}

After all, == works for comparing ints. Not only does it work, but it is the correct way to do primitive comparisons.

int i1 = 42;
int i2 = 40 + 2;

if ( i1 == i2 ) {
	//this is the proper way to compare ints
	System.out.println("Good code found here.");
}

Comparing Strings in Java with == is bad, because you are comparing String references and not String value equality. The reason this ever works is that equal String constants (meaning Strings that are defined with quotes) are stored internally at the same memory address. Strings defined in any other way are stored at unique memory addresses. That means Strings defined only using quotes are always equal when compared with ==, but not equal with Strings defined in any other way.

String s3 = "my string";

StringBuilder sb = new StringBuilder();
sb.append( "my" );
sb.append( " " );
sb.append( "string" );

String s4 = sb.toString();

if ( s3 == s4) {
	// this comparison evaluates to false
	System.out.println("What!?");
} else if ( s3.equals( s4 ) ) {
	// this comparison evaluates to true
	System.out.println("The equals() method beats the ==");
}

Even when you start out with two Strings defined using quotes, any manipulation of them places their values at a new memory locations. Here again, == becomes worthless for comparing the Strings.

String s5 = "my string";
String s6 = "my string  ".trim();

if ( s5 == s6) {
	// this comparison evaluates to false
	System.out.println("Figures");
} else if ( s5.equals( s6 ) ) {
	// this comparison evaluates to true
	System.out.println("String comparisons with == are fragile");
}

The moral of this story is that you should almost always use the equals() method for comparing Strings in Java. Yes, I said almost always.

Comparing Strings with == is faster than using the equals() method. When optimizing code in enterprise systems, a few milliseconds saved using a == over equals() may be worth the hassle (and danger) of working with == for comparisons.

In the rare situations where you need to use == for improving performance, you can use the intern() method to make Strings with otherwise unequal memory locations, equal. After you have manipulated or created a String, just call intern() on the String, and now it gains the memory location of every other equal String that has been created with quotes, or had intern() used on it.

String s5 = "my string";
String s6 = "my string  ".trim().intern();

if ( s5 == s6) {
	// now true!
	System.out.println("the intern() method fixed the comparison");
}

Sometimes you need to compare Strings, but ignore their case. Java has a method for that! Use the equalsIgnoreCase() method to compare two Strings for equality without using the capitalization in the comparison.

String s7 = "My String";
String s8 = "my string";

if ( s7.equalsIgnoreCase( s8 ) ) {
	// true!
	System.out.println("They're the same, except for case.");
}

Finally, when comparing a dynamically created String to a String literal, always use the string literal to call the equals method. Doing so prevents NullPointerExceptions when the dynamically set String happens to be null.

String myString = null;

if ( ! "my string".equals( myString ) ) {
	// not equal is true, *and* has no exceptions to handle
	System.out.println("Those pesky nulls! I tell you ...");
}

try {
	if ( ! myString.equals( "my string" ) ) {
		// Never get here, because of NullPointerException
		System.out.println("No truth for you!");
	}
} catch (NullPointerException npe) {
	npe.printStackTrace();
}