JB Header

Java String Comparison: == vs equals() vs compareTo()

Introduction Comparing strings is one of the most frequent operations in any program - checking a password, matching a command, sorting names. Java gives you several ways to do it, and choosing the wrong one is one of the most common Java bugs. This tutorial explains Java string comparison with ==, equals() and compareTo(). We will start with why == is the wrong way to compare strings. We will then compare contents with equals() and equalsIgnoreCase(), and handle null safely. Next we will put strings in order with compareTo(), and see how it decides which string comes first. Lastly, we will sort strings, and summarize which method to use when.

(Note - This tutorial builds on the Java String poolClick to read tutorial: Java String Pool: String Literals vs new String(), which explains why == sometimes appears to work.) == compares references, not contents For objects, == checks whether two variables refer to the same object in memory. Two different String objects with exactly the same characters are not ==. Because string literals are pooled, == often happens to work in small tests - and then fails when one string comes from user input, a file, or a calculation.
Why == is wrong for comparing strings
//DoubleEqualsTrap.java
import java.util.Scanner;

public class DoubleEqualsTrap {
  public static void main(String[] args) {
    String expected = "yes";
    String literal = "yes";
    System.out.println("literal == expected : " + (literal == expected));

    Scanner scanner = new Scanner(System.in);
    System.out.print("Continue? ");
    String answer = scanner.nextLine();
    System.out.println("answer == expected      : " + (answer == expected));
    System.out.println("answer.equals(expected) : " + answer.equals(expected));
  }
}
 OUTPUT of the above code
literal == expected : true
Continue? yes
answer == expected      : false
answer.equals(expected) : true
The user typed exactly yes, but == said false - the typed text is a new String object, not the pooled literal. Use == with strings only to check for null (s == null). equals() and equalsIgnoreCase() equals() compares the contents of two strings, character by character. It returns true only if both have the same length and the same characters in the same order - including case and spaces. equalsIgnoreCase() does the same, but treats upper- and lower-case letters as equal.
Comparing contents with equals() and equalsIgnoreCase()
//EqualsDemo.java
public class EqualsDemo {
  public static void main(String[] args) {
    String a = "Java";
    String b = new String("Java");
    String upper = "JAVA";
    String padded = " Java ";

    System.out.println("a.equals(b)                : " + a.equals(b));
    System.out.println("a.equals(upper)            : " + a.equals(upper));
    System.out.println("a.equalsIgnoreCase(upper)  : " + a.equalsIgnoreCase(upper));
    System.out.println("a.equals(padded)           : " + a.equals(padded));
    System.out.println("a.equals(padded.strip())   : " + a.equals(padded.strip()));
    System.out.println("\"\".equals(\"\")             : " + "".equals(""));
  }
}
 OUTPUT of the above code
a.equals(b)                : true
a.equals(upper)            : false
a.equalsIgnoreCase(upper)  : true
a.equals(padded)           : false
a.equals(padded.strip())   : true
"".equals("")             : true
Explanation of the code
  • a and b are different objects but have equal contents, so equals() returns true.
  • equals() is case-sensitive; equalsIgnoreCase() is not.
  • Leading and trailing spaces make strings unequal. User input is often cleaned with strip() (or the older trim()) before comparing.
Comparing with null safely Calling equals() on a null variable throws a NullPointerException. Two common ways to avoid it are to call equals() on the literal - which can never be null - or to use Objects.equals(), which handles null on either side.
null-safe string comparison
//NullSafeEquals.java
import java.util.Objects;

public class NullSafeEquals {
  public static void main(String[] args) {
    String command = null;
    System.out.println("\"quit\".equals(command)     : " + "quit".equals(command));
    System.out.println("Objects.equals(command, x) : " + Objects.equals(command, "quit"));
    System.out.println("Objects.equals(null, null) : " + Objects.equals(null, null));
    try {
      System.out.println(command.equals("quit"));
    } catch (NullPointerException e) {
      System.out.println("command.equals(...) threw a NullPointerException");
    }
  }
}
 OUTPUT of the above code
"quit".equals(command)     : false
Objects.equals(command, x) : false
Objects.equals(null, null) : true
command.equals(...) threw a NullPointerException
compareTo() - which string comes first? equals() only says whether two strings are the same. To put strings in order, use compareTo().
Definition of compareTo() in java.lang.String is -
public int compareTo(String anotherString)
Where,
  • it returns a negative number if this string comes before the other, zero if they are equal, and a positive number if it comes after.
  • the strings are compared character by character, from the start. At the first position where they differ, the result is the difference between the two characters' Unicode values.
  • if one string is a prefix of the other, the shorter one comes first, and the result is the difference in length.
Only the sign of the result is meaningful - do not rely on the exact number. compareToIgnoreCase() works the same way, but ignores case.
Ordering strings with compareTo()
//CompareToDemo.java
public class CompareToDemo {
  public static void main(String[] args) {
    System.out.println("\"apple\".compareTo(\"banana\") = " + "apple".compareTo("banana"));
    System.out.println("\"cherry\".compareTo(\"apple\") = " + "cherry".compareTo("apple"));
    System.out.println("\"Java\".compareTo(\"Java\")    = " + "Java".compareTo("Java"));
    System.out.println("\"Java\".compareTo(\"JavaScript\") = " + "Java".compareTo("JavaScript"));
    System.out.println("\"Zebra\".compareTo(\"apple\") = " + "Zebra".compareTo("apple"));
    System.out.println("\"Zebra\".compareToIgnoreCase(\"apple\") = " + "Zebra".compareToIgnoreCase("apple"));
    System.out.println("\"10\".compareTo(\"9\")          = " + "10".compareTo("9"));

    String first = "Harry", second = "Ethan";
    if (first.compareTo(second) < 0) {
      System.out.println(first + " comes before " + second);
    } else {
      System.out.println(second + " comes before " + first);
    }
  }
}
 OUTPUT of the above code
"apple".compareTo("banana") = -1
"cherry".compareTo("apple") = 2
"Java".compareTo("Java")    = 0
"Java".compareTo("JavaScript") = -6
"Zebra".compareTo("apple") = -7
"Zebra".compareToIgnoreCase("apple") = 25
"10".compareTo("9")          = -8
Ethan comes before Harry
Explanation of the code
  • 'a' (97) and 'b' (98) differ by 1, so "apple" comes 1 before "banana".
  • "Java" is a prefix of "JavaScript", so it comes first, and the result is the length difference, -6.
  • Case matters: all capital letters come before all lower-case letters in Unicode, so "Zebra" comes before "apple". compareToIgnoreCase() gives the dictionary order.
  • Numbers stored as strings are compared as text, so "10" comes before "9" (the character '1' is before '9'). Convert them to numbers to compare their values.
  • To use the result, test its sign - < 0, == 0 or > 0.
Sorting strings Sorting uses the same comparison. Arrays.sort() and Collections.sort() order strings by compareTo() - their natural order - unless you pass a different Comparator.
Sorting strings in natural and case-insensitive order
//SortingStrings.java
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class SortingStrings {
  public static void main(String[] args) {
    List<String> names = new ArrayList<>(List.of("tom", "Nancy", "ethan", "Harry", "deborah"));
    names.sort(null);                                  // natural order (compareTo)
    System.out.println("Natural     : " + names);
    names.sort(String.CASE_INSENSITIVE_ORDER);         // compareToIgnoreCase
    System.out.println("Ignore case : " + names);
    names.sort(Comparator.comparing(String::length));  // by length
    System.out.println("By length   : " + names);
  }
}
 OUTPUT of the above code
Natural     : [Harry, Nancy, deborah, ethan, tom]
Ignore case : [deborah, ethan, Harry, Nancy, tom]
By length   : [tom, ethan, Harry, Nancy, deborah]
For sorting by any rule - by length, by surname, in reverse - see The Complete Java 8 Comparator TutorialClick to read The Complete Java 8 Comparator Tutorial. Which one should you use?
  • a.equals(b) - are the contents the same? The default way to compare strings.
  • a.equalsIgnoreCase(b) - the same, ignoring case. Good for commands and answers such as "yes"/"YES".
  • "literal".equals(a) or Objects.equals(a, b) - when a may be null.
  • a.compareTo(b) - which comes first? For ordering and sorting.
  • a == b - only to check whether a is null, or (rarely) whether two variables refer to the very same object.
Summary In this tutorial we first saw that == compares references, so it fails for equal strings which are different objects - such as user input. We then compared contents with equals() and equalsIgnoreCase(), and handled null safely with the literal-first style and Objects.equals(). Next we put strings in order with compareTo(), and saw how it compares characters and handles prefixes and case. We then sorted strings in natural and case-insensitive order. Lastly, we summarized which comparison to use when. In the next tutorial, we will go through the essential String methodsClick to read tutorial: Essential Java String Methods with Examples.