How to compare strings in Java

There are six ways to compare strings in Java.
148 readers like this.
Javascript code close-up with neon graphic overlay

Photo by Jen Wike Huger

String comparison is a fundamental operation in programming and is often quizzed during interviews. These strings are a sequence of characters that are immutable which means unchanging over time or unable to be changed.

Java has a number of methods for comparing strings; this article will teach you the primary operation of how to compare strings in Java.

There are six options:

  1. The == operator
  2. String equals
  3. String equalsIgnoreCase
  4. String compareTo
  5. String compareToIgnoreCase
  6. Objects equals

The == operator

== is an operator that returns true if the contents being compared refer to the same memory or false if they don't. If two strings compared with == refer to the same string memory, the return value is true; if not, it is false.

String string1 = "MYTEXT";
String string2 = "YOURTEXT";
		
System.out.println("Output: " + (string1 == string2));

Output: false

The return value of == above is false, as "MYTEXT" and "YOURTEXT" refer to different memory.

String string1 = "MYTEXT";
String string6 = "MYTEXT";
		
System.out.println("Output: " + (string1 == string6));

Output: true

In this case, the return value of == is true, as the compiler internally creates one memory location for both "MYTEXT" memories, and both variables refer to the same memory location.

String string1 = "MYTEXT";
String string7 = string1;

System.out.println("Output: " + (string1 == string7));

Output: true

If you guessed right, you know string7 is initialized with the same memory location as string1 and therefore == is true.

String string1 = "MYTEXT";
String string4 = new String("MYTEXT");

System.out.println("Output: " + (string1 == string4));

Output: false

In this case, the compiler creates a new memory location, even though the value is the same for string4 and string1.

String string1 = "MYTEXT";
String string5 = new String(string1);

System.out.println("Output: " + (string1 == string4));

Output: false

Here, string5 is a new string object initialized with string1; hence, string1 == string4 is not true.

String equals

The string class has a String equals method to compare two strings. String comparison with equals is case-sensitive. According to the docs:

    /**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) { ... }

Let's see a few examples:

String string1 = "MYTEXT";
String string2 = "YOURTEXT";

System.out.println("Output: " + string1.equals(string2));

Output: false

If the strings are not the same, the output of the equals method is obviously false.

String string1 = "MYTEXT";
String string3 = "mytext";

System.out.println("Output: " + string1.equals(string3));

Output: false

These strings are the same in value but differ in case; hence, the output is false.

String string1 = "MYTEXT";
String string4 = new String("MYTEXT");

System.out.println("Output: " + string1.equals(string4));

Output: true
String string1 = "MYTEXT";
String string5 = new String(string1);

System.out.println("Output: " + string1.equals(string5));

Output: true

The examples in both these cases are true, as the two values are the same. Unlike with ==, the second example above returns true.

The string object on which equals is called should obviously be a valid string object and non-null.

String string1 = "MYTEXT";
String string8 = null;

System.out.println("Output: " + string8.equals(string1));

Exception in thread _____  java.lang.NullPointerException

The above evidently is not a good code.

System.out.println("Output: " + string1.equals(string8));

Output: false

This is alright.

String equalsIgnoreCase

The behavior of equalsIgnoreCase is identical to equals with one difference—the comparison is not case-sensitive. The docs say:

    /**
     * Compares this {@code String} to another {@code String}, ignoring case
     * considerations.  Two strings are considered equal ignoring case if they
     * are of the same length and corresponding characters in the two strings
     * are equal ignoring case.
     *
     * <p> Two characters {@code c1} and {@code c2} are considered the same
     * ignoring case if at least one of the following is true:
     * <ul>
     *   <li> The two characters are the same (as compared by the
     *        {@code ==} operator)
     *   <li> Applying the method {@link
     *        java.lang.Character#toUpperCase(char)} to each character
     *        produces the same result
     *   <li> Applying the method {@link
     *        java.lang.Character#toLowerCase(char)} to each character
     *        produces the same result
     * </ul>
     *
     * @param  anotherString
     *         The {@code String} to compare this {@code String} against
     *
     * @return  {@code true} if the argument is not {@code null} and it
     *          represents an equivalent {@code String} ignoring case; {@code
     *          false} otherwise
     *
     * @see  #equals(Object)
     */
    public boolean equalsIgnoreCase(String anotherString) { ... }

The second example in equals (above) is the only difference from the comparison in equalsIgnoreCase.

String string1 = "MYTEXT";
String string3 = "mytext";

System.out.println("Output: " + string1.equalsIgnoreCase(string3));

Output: true

This returns true because the comparison is case-independent. All other examples under equals remain the same as they are for equalsIgnoreCase.

String compareTo

The compareTo method compares two strings lexicographically (i.e., pertaining to alphabetical order) and case-sensitively and returns the lexicographical difference in the two strings. The docs describe lexicographical order computation as:

/**
     * Compares two strings lexicographically.
     * The comparison is based on the Unicode value of each character in
     * the strings. The character sequence represented by this
     * {@code String} object is compared lexicographically to the
     * character sequence represented by the argument string. The result is
     * a negative integer if this {@code String} object
     * lexicographically precedes the argument string. The result is a
     * positive integer if this {@code String} object lexicographically
     * follows the argument string. The result is zero if the strings
     * are equal; {@code compareTo} returns {@code 0} exactly when
     * the {@link #equals(Object)} method would return {@code true}.
     * <p>
     * This is the definition of lexicographic ordering. If two strings are
     * different, then either they have different characters at some index
     * that is a valid index for both strings, or their lengths are different,
     * or both. If they have different characters at one or more index
     * positions, let <i>k</i> be the smallest such index; then the string
     * whose character at position <i>k</i> has the smaller value, as
     * determined by using the &lt; operator, lexicographically precedes the
     * other string. In this case, {@code compareTo} returns the
     * difference of the two character values at position {@code k} in
     * the two string -- that is, the value:
     * <blockquote><pre>
     * this.charAt(k)-anotherString.charAt(k)
     * </pre></blockquote>
     * If there is no index position at which they differ, then the shorter
     * string lexicographically precedes the longer string. In this case,
     * {@code compareTo} returns the difference of the lengths of the
     * strings -- that is, the value:
     * <blockquote><pre>
     * this.length()-anotherString.length()
     * </pre></blockquote>
     *
     * @param   anotherString   the {@code String} to be compared.
     * @return  the value {@code 0} if the argument string is equal to
     *          this string; a value less than {@code 0} if this string
     *          is lexicographically less than the string argument; and a
     *          value greater than {@code 0} if this string is
     *          lexicographically greater than the string argument.
     */
    public int compareTo(String anotherString) { ... }

Let's look at some examples.

String string1 = "A";
String string2 = "B";

System.out.println("Output: " + string1.compareTo(string2));

Output: -1
System.out.println("Output: " + string2.compareTo(string1));

Output: 1
String string1 = "A";
String string3 = "a";

System.out.println("Output: " + string1.compareTo(string3));

Output: -32

System.out.println("Output: " + string3.compareTo(string1));

Output: 32
String string1 = "A";
String string6 = "A";
		
	System.out.println("Output: " + string1.compareTo(string6));

Output: 0
String string1 = "A";
String string8 = null;
		
System.out.println("Output: " + string8.compareTo(string1));

Exception in thread ______  java.lang.NullPointerException
at java.lang.String.compareTo(String.java:1155)

String string1 = "A";
String string10 = "";
		
System.out.println("Output: " + string1.compareTo(string10));

Output: 1

String compareToIgnoreCase

The behavior of compareToIgnoreCase is identical to compareTo with one difference: the strings are compared without case consideration.

String string1 = "A";
String string3 = "a";

System.out.println("Output: " + string1.compareToIgnoreCase(string3));

Output: 0

Objects equals

The Objects equals method invokes the overridden String equals method; its behavior is the same as in the String equals example above.

String string1 = "MYTEXT";
String string2 = "YOURTEXT";

System.out.println("Output: " + Objects(string1, string2));

Output: false
String string1 = "MYTEXT";
String string3 = "mytext";

System.out.println("Output: " + Objects(string1, string3));

Output: false
String string1 = "MYTEXT";
String string6 = "MYTEXT";

System.out.println("Output: " + Objects(string1, string6));

Output: true
String string1 = "MYTEXT";
String string8 = null;

System.out.println("Output: " + Objects.equals(string1, string8));

Output: false

System.out.println("Output: " + Objects.equals(string8, string1));

Output: false
String string8 = null;
String string9 = null;

System.out.println("Output: " + Objects.equals(string8, string9)); 

Output: true

The advantage here is that the Objects equals method checks for null values (unlike String equals). The implementation of Object equals is:

public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}

Which method to use?

There are many methods to compare two strings. Which one should you use? As a common practice, use String equals for case-sensitive strings and String equalsIgnoreCase for case-insensitive comparisons. However, one caveat: take care of NPE (NullPointerException) if one or both strings are null.

The source code is available on GitLab and GitHub.

What to read next

Why I use Java

There are probably better languages than Java, depending on work requirements. But I haven't seen anything yet to pull me away.

Tags
User profile image.
Girish has over 20 years’ experience in technology and software at a global IT Services organization based in India. Girish is architect of "I Got" cloud platform to uplift the bottom of the pyramid built with open source stack and contemporary architectural patterns such as microservices, containerisation and multi tenancy. Girish writes on open source and tech topics.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.