How to Compare two Strings in Java How to Compare two Strings in Java

Page content

In this tutorial, we’ll learn different ways to compare two strings in Java

Compare Strings using “==” operator

 1String string1 = "CodingNConcepts";
 2String string2 = "CodingNConcepts";
 3String string3 = new String("CodingNConcepts");
 4String string4 = new String("CodingNConcepts");
 5
 6System.out.println(string1 == string2);    // true
 7System.out.println(string1 == string3);    // false
 8System.out.println(string3 == string4);    // false
 9
10string3 = string3.intern();
11string4 = string4.intern();
12
13System.out.println(string1 == string3);    // true
14System.out.println(string3 == string4);    // true
Explanation
  • line 6: string1 and string2 both are initialized using literal so they both are referring to same string stored in String-Pool
  • line 7: string3 is initialized using New so it always creates a new string object in Java heap memory whereas string1 refers to string from String-Pool
  • line 8: Since String initialized using New always create a new string object, string3 and string4 both refers to different string object in heap memory
  • line 10,11: When you call intern() on a string, it returns a string from String-Pool if exist otherwise a new string is created in String-Pool and returned.
    So now after executing line 10 and 11, string3 and string4 refers to same string from String-Pool
  • line 13,14: After executing line 10 and 11, all four strings string1, string2, string3 and string4 refers to same string from String-Pool

Compare Strings using equals() method

String’s equals() method - returns true if the string argument is not null and both the comparing strings have the same sequence of characters in same case.

1String string1 = "CodingNConcepts";
2String string2 = "CodingNConcepts";
3String string3 = new String("CodingNConcepts");
4String string4 = new String("CODINGNCONCEPTS");
5
6System.out.println(string1.equals(string2));   // true
7System.out.println(string1.equals(string3));   // true
8System.out.println(string1.equals(string4));   // false
9System.out.println(string1.equals(null));      // false
Explanation
  • line 6: string1 and string2 both have same character sequence
  • line 7: string1 and string3 both have same character sequence
  • line 8: string1 and string4 both have same character sequence but case is different
  • line 9: string argument is null

Compare Strings ignoring case using equalsIgnoreCase()

If you don’t care about case — say you’re matching a username or a file extension — equalsIgnoreCase() does the same character-by-character comparison as equals() but treats corresponding upper and lower case letters as identical.

1String string1 = "CodingNConcepts";
2String string4 = new String("CODINGNCONCEPTS");
3
4System.out.println(string1.equals(string4));            // false
5System.out.println(string1.equalsIgnoreCase(string4));  // true

Internally it’s not just “lowercase both and compare” — that would break on a handful of locale-sensitive characters (like the Turkish dotless ı). equalsIgnoreCase() uses Character.toUpperCase()/toLowerCase() per character with the extra fallback logic needed to handle those edge cases correctly, so prefer it over rolling your own .toLowerCase().equals(...) check.

Compare Strings for ordering using compareTo() and compareToIgnoreCase()

equals() only answers “are these the same?”. When you need to know which one comes first — for sorting, for a TreeMap/TreeSet key, for binary search — you need compareTo(), which implements Comparable<String>.

1String a = "apple";
2String b = "banana";
3
4System.out.println(a.compareTo(b));   // -1
5System.out.println(b.compareTo(a));   // 1
6System.out.println(a.compareTo("apple"));  // 0

A common misconception is that compareTo() only ever returns -1, 0, or 1. It doesn’t — the Java specification only guarantees the sign. The actual magnitude is the numeric difference between the Unicode values of the first pair of characters that differ:

1System.out.println("app".compareTo("apple"));   // -2  (i.e. "app".length() - "apple".length())
2System.out.println("apple".compareTo("app"));    // 2
3System.out.println("a".compareTo("c"));          // -2  ('a' is 97, 'c' is 99)

If the strings are equal up to the length of the shorter one, the result is simply the difference in their lengths (that’s the -2 in the first example — "app" is 2 characters shorter than "apple"). Otherwise it’s thisChar - otherChar at the first mismatch. Never write code that depends on the exact number — only ever check whether the result is negative, zero, or positive.

compareToIgnoreCase() does the same thing but case-insensitively, using the same character-normalization rules as equalsIgnoreCase():

1System.out.println("Apple".compareToIgnoreCase("apple"));  // 0

Null-safe comparison with Objects.equals()

string1.equals(argument) is null-safe on the argument — passing null in just returns false. It is not safe when the variable you’re calling .equals() on is itself null:

1String nullString = null;
2String other = "test";
3
4System.out.println(nullString.equals(other));  // throws NullPointerException

This is a frequent source of NullPointerException in code that compares a value that might not have been initialized (a field read from a database, a missing HTTP header, an optional config value) against a known constant. The fix is either to put the known non-null value first ("test".equals(nullString) returns false safely) or, more explicitly, to use Objects.equals(), which handles both sides being null:

1System.out.println(Objects.equals(nullString, other));  // false, no exception
2System.out.println(Objects.equals(null, null));         // true

Objects.equals(a, b) is just a short-circuit: it returns true if both references are the same object (covers the null == null case), otherwise false if either is null, otherwise delegates to a.equals(b). It reads better than a != null && a.equals(b) scattered through a codebase and it’s the standard, idiomatic way to write null-safe equality checks.

Why using == for content is a classic bug

The == examples earlier in this post aren’t just trivia — they explain a real production bug pattern. String literals get interned automatically, so two literals with the same text often do pass == — which is exactly what makes the bug dangerous: it works by accident in a quick test.

1String input = new Scanner(System.in).nextLine(); // e.g. user types "admin"
2
3if (input == "admin") {   // almost always false, even when input IS "admin"
4    System.out.println("Welcome, admin!");
5}

Strings that come from Scanner, HTTP request parameters, file reads, substring(), new String(...), deserialization, or string concatenation built at runtime are not guaranteed to be interned, so == compares object identity, not content — and it will silently fail exactly when it matters (real user input), even though the same check “worked” in a unit test built entirely from literals. This is one of the most common Java bugs reported by static analyzers like SpotBugs and SonarQube — treat any == on a String as a bug unless you specifically intend a reference-identity check (e.g., checking against a switch-optimized constant, or after an explicit .intern() call).

Which method should you use?

Goal Use
Content equality, case-sensitive equals()
Content equality, case-insensitive equalsIgnoreCase()
Sorting / ordering / TreeMap keys compareTo() (or compareToIgnoreCase())
Either value might be null Objects.equals(a, b)
Reference identity (rare, intentional) ==

As a rule of thumb: reach for equals() by default, compareTo() when order matters, and Objects.equals() whenever a null is plausible — and never == for content comparison, no matter how convincing it looks in a quick REPL test.