Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Avoid Comparing strings with == in Java

4.25/5 (3 votes)
19 Nov 2013CPOL2 min read 7.2K  
Avoid comparing strings with == in Java

Introduction

While beginning development in Java, especially if coming from a .NET background (but not necessarily), you might do string comparison with == in Java. Don’t do it. It will compare the string instances and not their effective value. You might even try it first to check if == really works, testing it in a wrong manner like so:

Java
public static void main(String[] args) {

    String s1 = "Abc";
    String s2 = "Abc";

    System.out.println("s1 == s2 -> " + (s1 == s2));
}

This will output:

s1 == s2 -> true

.. which might lead you to believe this works. This does return the correct value because of a feature present in Java and .NET called string interning (not specific to Java or .NET).

Try to obtain a string instance dynamically like concatenating two existing instances and see how things don’t work anymore:

Java
public static void main(String[] args) {

    String s1 = "Abc";
    String s2 = "Abc";

    // new lines :
    String capitalA = "A";
    String bc = "bc";
    String s3 = capitalA + bc;

    System.out.println("s1 == s2 -> " + (s1 == s2));
    // new line :
    System.out.println("s1 == s3 -> " + (s1 == s3));
}
s1 == s2 -> true
s1 == s3 -> false

Weird, huh? That’s because at compile time, there are four distinct strings generated: “Abc” (once, even if referred twice), “A” and “bc”. The “Abc” instance obtained by joining “A” and “bc” will be generated at runtime and, of course, it will be a different instance than the first “Abc” instance. That’s why the result of the == operator comparison will be false.

But the compiler can be smarter than you might expect. How’s that? Here’s how:

Java
public static void main(String[] args) {

    String s1 = "Abc";
    String s2 = "Abc";

    String capitalA = "A";
    String bc = "bc";
    String s3 = capitalA + bc;

    // new line
    String s4 = "A" + "bc";

    System.out.println("s1 == s2 -> " + (s1 == s2));
    System.out.println("s1 == s3 -> " + (s1 == s3));
    // new line
    System.out.println("s1 == s4 -> " + (s1 == s4));
}

.. resulting in:

s1 == s2 -> true
s1 == s3 -> false
s1 == s4 -> true

The compiler inferred the result of the string concatenation in the s4 initialization and then interned the resulted string, detected the already existing “Abc” instance and reused it.

Alright, that’s not the right way to do it, the correct way to do it is to use the .equals(String s) instance method of the String class. Like so:

Java
public static void main(String[] args) {

    String s1 = "Abc";

    String capitalA = "A";
    String bc = "bc";
    String s2 = capitalA + bc;

    System.out.println("s1.equals(s2) -> " +  s1.equals(s2));
}

This works nice:

s1.equals(s2) -> true

All’s well until we tweak things a bit:

Java
public static void main(String[] args) {

    String s1 = null;
    String s2 = null;

    System.out.println("s1.equals(s2) -> " +  s1.equals(s2));
}

Guess what, it’s not “true” that’s being displayed but the stack trace of a NullPointerException. Your solution might be some weird ternary expression (yuck) that looks like so:

Java
public static void main(String[] args) {

    String s1 = null;
    String s2 = null;

    boolean b = s1 == null ? s2 == s1 : s1.equals(s2);
    System.out.println(b);
}

You can extract this expression into a static method in a helper class if you find yourself doing this often.

As a final aspect to consider, if one of the two strings is a constant value, you can still use equals on that one like so:

Java
public static void main(String[] args) {

    String s1 = getData();
    String s2 = "someValue";

    System.out.println(s2.equals(s1));
    System.out.println("someOtherValue".equals(s1));
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)