== vs .equals() for Strings in Java
Fast recall
Quick revision
Core answer
== tests whether two references denote the same object, while equals() compares the sequence of UTF-16 code units. Equal literals may be the same interned object, so == can appear to work and then fail for an equal string built at runtime. Use equals() for content and Objects.equals(a, b) when either value may be null.Whether you know that == checks address and .equals() checks content, and can explain why == sometimes works by accident (String pool) but is unreliable.
Saying == works fine for Strings because it works during simple tests with literals. It fails the moment a String comes from user input, a file read, a REST response, or new String().
Mention equalsIgnoreCase() for case-insensitive comparison, and Objects.equals(s1, s2) as the null-safe way to compare without a NullPointerException.
Interview-ready guide
Interview answer
Here is the thing candidates get burned by: == looks like it works for Strings, right up until it doesn't. It compares references — whether two variables point to the same object in memory — not the actual text. So it only returns true when both sides are literally the same object.
The reason it seems to work is the String pool. When you write two identical literals, Java hands you the same pooled object, so == happens to return true. But the moment a String comes from scanner.nextLine(), a REST response, a database read, or new String("hello"), you have a brand-new heap object — and == returns false even though the text is identical. That is the silent bug: it passes every quick test with literals and breaks in production with real input.
So my rule is simple — .equals() for any String content comparison, always. It walks the characters and does not care how the String was created.
Two things I would add to show I have actually hit this. First, null-safety: I write "hello".equals(variable) so a null variable cannot throw a NullPointerException, or I reach for Objects.equals(a, b) which handles nulls on both sides. And if case should not matter, equalsIgnoreCase() is cleaner than lowercasing by hand. Bottom line: == is identity, .equals() is content — and for Strings it is .equals() every time.
== vs .equals() for Strings in Java
Direct Answer
For strings, == tests whether two references denote the same object, while equals() compares the sequence of UTF-16 code units. Equal literals may be the same interned object, so == can appear to work and then fail for an equal string built at runtime. Use equals() for content and Objects.equals(a, b) when either value may be null.
Code Example
public class StringCompareDemo {
public static void main(String[] args) {
String s1 = "hello"; // literal → goes to pool
String s2 = "hello"; // literal → same pooled object
String s3 = new String("hello"); // always new heap object
System.out.println(s1 == s2); // true — accident of the pool
System.out.println(s1 == s3); // false — different objects
System.out.println(s1.equals(s2)); // true
System.out.println(s1.equals(s3)); // true — content matches
// The real-world case where == silently breaks:
String fromUser = new String("hello"); // simulates scanner/API input
if (fromUser == "hello") { // FALSE — always, even if text matches
System.out.println("Won't print");
}
if (fromUser.equals("hello")) { // TRUE — correct
System.out.println("Match!");
}
// Null-safe pattern — put the literal first to avoid NullPointerException
String maybeNull = null;
// maybeNull.equals("hello") // NullPointerException
System.out.println("hello".equals(maybeNull)); // false — safe
System.out.println(java.util.Objects.equals(maybeNull, "hello")); // false — null-safe
}
}
Common Mistakes & Pitfalls
- Using
==to compare String content — it passes with literals because of the pool, then fails the instant the String comes from input, a file, an API, ornew String(). - Calling
.equals()on a possibly-null variable —name.equals("admin")throwsNullPointerExceptionwhennameisnull; flip it to"admin".equals(name)or useObjects.equals(). - Assuming
new String("hello") == "hello"istrue—new String(...)always allocates a fresh heap object, so==isfalseeven though the characters match. - Leaning on
intern()to make==work — interning forces pool membership, but code that depends on==for content is fragile; just call.equals().
Check your understanding
Answer these without looking back at the article.
- What is the String pool and how does it affect == comparison?
- What is equalsIgnoreCase() and when do you use it?
- What does Objects.equals() do and how is it null-safe?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.