1. Introduction

Comparing strings in Java seems straightforward, but different comparison methods answer different questions. For example, == checks whether two references point to the same object, while equals() checks whether their character content is equal. For ordering strings, Java provides compareTo() and compareToIgnoreCase().


Premium Video

This video is available to Premium members or users who have purchased the course.

Sign in to Unlock

Choosing the wrong method can create subtle bugs when comparing coupon codes, customer input, file contents, product names, or values loaded from a database.

This guide explains the main comparison methods, null safety, sorting, Unicode-related considerations, and the relationship between equals() and hashCode(). All complete Java programs use public class Main and public static void main(String[] args).

2. Learning Objectives

After reading this guide, you should be able to:

  • Distinguish reference identity from string-content equality.
  • Use equals() and equalsIgnoreCase() appropriately.
  • Interpret the sign returned by compareTo() and compareToIgnoreCase().
  • Compare strings safely when null values are possible.
  • Sort strings with natural and case-insensitive ordering.
  • Recognize when human-language sorting requires Collator.
  • Understand how equals() and hashCode() work together in hash-based collections.

3. Reference Identity vs. Content Equality

For primitive values such as int and double, == compares values. For reference types such as String, == compares references: it asks whether both variables refer to the same object.

That is different from asking whether the strings contain the same characters.

Output

true
false
true

String literals are interned, so identical literals normally refer to the same pooled object. The new String("laptop") expression creates a distinct String object. The content is still the same, which is why equals() returns true.

Rule: use == only when reference identity is the question. For ordinary text comparison, use equals().

4. The equals() Method

String.equals(Object obj) compares content. It returns true when the argument is a String with the same sequence of characters in the same order.

Output

true
false
false
false

Important details:

  • Comparing a non-null string to null with equals() returns false.
  • Passing a non-String object, such as StringBuilder, also returns false.
  • Calling .equals() on a reference that is itself null throws NullPointerException.
  • Content equality is case-sensitive: "save10" and "SAVE10" are different strings.

The usual time complexity is \(O(n)\) in the string length. Implementations can reject strings of different lengths quickly, so a length mismatch may be handled in \(O(1)\) time.

5. equalsIgnoreCase() for Case-Insensitive Equality

When case should not matter, use equalsIgnoreCase().

Output

false
true

equalsIgnoreCase() compares the strings without regard to case. It avoids the need to create lowercase copies just to compare them.

Unicode and locale note

Case-insensitive comparison is not identical to applying a language-specific collation rule. Some non-ASCII characters have case behavior that may not match every user's expectations. For multilingual product catalogs, consider whether simple case-insensitive equality is sufficient for the product requirements.

Typical comparison cost is \(O(n)\), with early exit possible when a mismatch is found.

6. compareTo() and Lexicographic Ordering

equals() answers whether strings match. compareTo() provides an ordering, which is useful for sorting or determining which string comes first according to Java's natural string order.

For a.compareTo(b):

  • A negative result means a sorts before b.
  • Zero means the strings have equal content.
  • A positive result means a sorts after b.

Do not rely on the exact magnitude of the returned integer. The contract guarantees the sign, not a particular numerical distance.

Output

true
true
true

How the comparison works

Java's natural String order is lexicographic based on UTF-16 code units. The comparison proceeds from left to right until it finds a difference or reaches the end of one string.

If one string is a prefix of the other, the shorter string sorts first. For example, "lap" sorts before "laptop".

Output

true
true
true

For basic ASCII letters, uppercase letters sort before lowercase letters because uppercase code values are lower. This is not the same as human dictionary order for every language.

Correct way to use the result

Avoid treating the returned integer as a count of characters or a meaningful distance. Use only its sign:

Output

 first comes before second

The cost is typically proportional to the common prefix length plus the first differing position, bounded by the lengths of the strings.

7. compareToIgnoreCase()

compareToIgnoreCase() provides ordering without treating case differences as significant.

Output

false
true

Use compareToIgnoreCase() when you need both ordering and case-insensitive comparison. For yes-or-no equality only, equalsIgnoreCase() is clearer.

Like compareTo(), its natural ordering is not a complete substitute for language-specific dictionary ordering.

8. Null Safety

Methods such as equals() and compareTo() are instance methods. The reference to the left of the dot must not be null.

This program throws NullPointerException because couponCode is null.

Pattern 1: Put a known non-null literal on the left

Output

 false

The literal cannot be null, and String.equals(null) returns false.

Pattern 2: Use Objects.equals()

Objects.equals(a, b) is a static helper that safely compares two references:

  • Both are null → true
  • Exactly one is null → false
  • Neither is null → delegates to a.equals(b)

Output

true
false
true

Objects.equals() is useful when either side may be null. It does not make compareTo() null-safe; sorting nullable values requires a comparator that explicitly defines how nulls should be ordered.

9. The == vs. equals() Pitfall with User Input

A common mistake is comparing input read from a Scanner with ==.

Even if the user enters SAVE10, == checks whether the two references point to the same object, not whether their content matches. The condition will usually be false.

Correct version

Example run

Enter coupon code: save10
Coupon rejected

This corrected version is null-safe, but it is still case-sensitive. For case-insensitive matching, replace the condition with "SAVE10".equalsIgnoreCase(entered).

10. Sorting Strings

Arrays and collections can sort strings using their natural ordering, which is based on compareTo(). Because the comparison is case-sensitive, uppercase and lowercase names may appear in an unexpected order for a product catalog.

Output

 [Headphones, Laptop, Monitor, keyboard, mouse]

Case-insensitive sorting with String.CASE_INSENSITIVE_ORDER


Output

 [Headphones, keyboard, Laptop, Monitor, mouse]

String.CASE_INSENSITIVE_ORDER is a built-in comparator for case-insensitive string ordering.

Sorting with a custom comparator

Comparator.comparing() lets you sort by a derived value, such as string length.

Output

 [Mouse, Laptop, Monitor, Keyboard]

For equal lengths, the comparator returns zero, and the sorting behavior preserves the relative order of equal elements for object-array sorting.

11. Human-Language Ordering with Collator

compareTo() compares UTF-16 code units. It is not designed to match every language's dictionary rules for accented characters. For locale-sensitive sorting, Java provides java.text.Collator.


The exact collation order can depend on the locale data in the JDK, but Collator is designed to apply language-aware comparison rules instead of raw UTF-16 ordering.

Use Collator when sorting multilingual catalogs, names, or labels according to the expectations of a particular language. For simple English identifiers, natural or case-insensitive ordering is often sufficient.

12. Complexity and Performance

Let \(n\) be the length of the compared strings.

OperationTypical complexityNotes
equals()\(O(n)\) worst caseCan return early for different lengths or an early mismatch.
equalsIgnoreCase()\(O(n)\) worst caseStops at the first mismatch.
compareTo()\(O(n)\) worst caseScans until a difference or the end of a string.
compareToIgnoreCase()\(O(n)\) worst caseCase-insensitive lexicographic comparison.
hashCode() first calculation\(O(n)\)String hash values are cached by the implementation; later calls are typically \(O(1)\).
Sorting \(n\) stringsAbout \(O(n \log n)\) comparisonsEach comparison may inspect a common prefix, so long similar strings add cost.

These are general algorithmic expectations; actual performance depends on string lengths, common prefixes, JVM implementation, and the sorting workload.

13. The equals() and hashCode() Contract

Java requires that if a.equals(b) is true, then a.hashCode() and b.hashCode() must be equal. Strings follow this contract.

Output

false
true
true
25

The strings are distinct objects, but they have equal content and matching hash codes. This is why a HashMap can find a value using a separately constructed string with the same content.

Because String is immutable, its content-based hash code remains stable for its lifetime. That makes strings reliable keys in hash-based collections.

14. Choosing the Right Comparison Method

Whiteboard
Loading diagram...

Quick method table

RequirementRecommended method
Exact content equality, case-sensitiveequals()
Content equality, case-insensitiveequalsIgnoreCase()
Lexicographic orderingcompareTo()
Case-insensitive orderingcompareToIgnoreCase()
Case-insensitive sortingString.CASE_INSENSITIVE_ORDER
Null-safe equalityObjects.equals(a, b)
Locale-aware human-language sortingCollator
Reference identity== (rarely needed for string content)

15. Common Mistakes and Best Practices

Common mistakes

  • Using == when content equality is intended.
  • Calling .equals() or .compareTo() on a reference that may be null.
  • Assuming compareTo() returns only -1, 0, or 1.
  • Treating natural string order as universal dictionary order.
  • Using case-insensitive equality when the application requires locale-specific text rules.
  • Comparing a String directly with a StringBuilder and expecting equal content to count as equal objects.
  • Sorting a multilingual catalog with raw UTF-16 ordering when users expect language-aware collation.

Best practices

  • Use equals() for ordinary case-sensitive text equality.
  • Use equalsIgnoreCase() when case differences should not matter.
  • Use compareTo() or a comparator when ordering is required.
  • Check only the sign of a compareTo() result.
  • Use "KNOWN_VALUE".equals(variable) or Objects.equals(a, b) for null-safe equality.
  • Use String.CASE_INSENSITIVE_ORDER for straightforward case-insensitive sorting.
  • Use Collator when locale-aware ordering is required.
  • Keep the equals()/hashCode() contract in mind when using strings as map or set keys.

16. Quick Revision Notes

  • == compares references for String; it does not compare character content.
  • equals() compares exact content and is case-sensitive.
  • equalsIgnoreCase() compares content without treating case differences as significant.
  • compareTo() and compareToIgnoreCase() provide ordering; check whether the result is negative, zero, or positive.
  • A null receiver causes instance-method calls to fail with NullPointerException.
  • Objects.equals(a, b) handles null values on either side.
  • String.CASE_INSENSITIVE_ORDER provides a ready-made case-insensitive comparator.
  • Collator is appropriate for locale-sensitive human-language sorting.
  • Equal strings have equal hash codes, making them reliable HashMap keys.
  • Use == only when reference identity is specifically what you want.

17. Conclusion

Java offers different string comparison methods because equality, identity, case-insensitive matching, and ordering are different tasks. For ordinary content comparison, equals() is the standard choice. Use equalsIgnoreCase() when case should not matter, compareTo() when natural ordering is needed, and a suitable comparator or Collator when sorting requirements are more specific.

Handle possible null values deliberately, never depend on the exact magnitude of a compareTo() result, and remember that String content equality and hash codes work together. Choosing the right method makes string-based validation, searching, sorting, and collection lookups more reliable.