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 UnlockChoosing 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()andequalsIgnoreCase()appropriately. - Interpret the sign returned by
compareTo()andcompareToIgnoreCase(). - 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()andhashCode()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
nullwithequals()returnsfalse. - Passing a non-
Stringobject, such asStringBuilder, also returnsfalse. - Calling
.equals()on a reference that is itselfnullthrowsNullPointerException. - 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
asorts beforeb. - Zero means the strings have equal content.
- A positive result means
asorts afterb.
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 secondThe 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
falseThe 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 toa.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.
| Operation | Typical complexity | Notes |
|---|---|---|
equals() | \(O(n)\) worst case | Can return early for different lengths or an early mismatch. |
equalsIgnoreCase() | \(O(n)\) worst case | Stops at the first mismatch. |
compareTo() | \(O(n)\) worst case | Scans until a difference or the end of a string. |
compareToIgnoreCase() | \(O(n)\) worst case | Case-insensitive lexicographic comparison. |
hashCode() first calculation | \(O(n)\) | String hash values are cached by the implementation; later calls are typically \(O(1)\). |
| Sorting \(n\) strings | About \(O(n \log n)\) comparisons | Each 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
Quick method table
| Requirement | Recommended method |
|---|---|
| Exact content equality, case-sensitive | equals() |
| Content equality, case-insensitive | equalsIgnoreCase() |
| Lexicographic ordering | compareTo() |
| Case-insensitive ordering | compareToIgnoreCase() |
| Case-insensitive sorting | String.CASE_INSENSITIVE_ORDER |
| Null-safe equality | Objects.equals(a, b) |
| Locale-aware human-language sorting | Collator |
| 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, or1. - Treating natural string order as universal dictionary order.
- Using case-insensitive equality when the application requires locale-specific text rules.
- Comparing a
Stringdirectly with aStringBuilderand 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)orObjects.equals(a, b)for null-safe equality. - Use
String.CASE_INSENSITIVE_ORDERfor straightforward case-insensitive sorting. - Use
Collatorwhen 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 forString; it does not compare character content.equals()compares exact content and is case-sensitive.equalsIgnoreCase()compares content without treating case differences as significant.compareTo()andcompareToIgnoreCase()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_ORDERprovides a ready-made case-insensitive comparator.Collatoris appropriate for locale-sensitive human-language sorting.- Equal strings have equal hash codes, making them reliable
HashMapkeys. - 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.