In Java, String is immutable — once created it can't change; any 'modification' makes a new object. This, plus the difference between == (reference equality) and .equals() (content equality), and the string pool, drives the most common Java traps. Wrapper classes and autoboxing add a couple more.
== vs equals, and immutability
== compares references (do two variables point to the same object?); .equals() compares content. Because String is immutable, methods like concat or + return new strings rather than changing the original. For lots of concatenation, use the mutable StringBuilder.
== vs equals on strings
String a = new String("hi");
String b = new String("hi");
System.out.println(a == b); // false (different objects)
System.out.println(a.equals(b)); // true (same content)
String c = "hi", d = "hi"; // string literals -> same pooled object
System.out.println(c == d); // true (interned in the string pool)StringBuilder for many edits
StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) sb.append(i); // efficient: one growing buffer String result = sb.toString();
⚡ The edge
- Use .equals() to compare String content; == compares object references. String literals are interned in a shared pool, so two equal literals can be ==, but new String("x") always makes a distinct object — the classic trap.
- String is immutable, so building a string in a loop with + creates many throwaway objects. Use StringBuilder (mutable) for repeated concatenation — it grows one buffer instead.
Worked example
Why does a == b give false but a.equals(b) give true for two new Strings?
- new String("hi") creates a brand-new object each time, so a and b are different objects in memory.
- == compares references, so a == b is false (different objects).
- equals compares content, and both contain "hi", so a.equals(b) is true. Always use equals for String content.
Answer: == compares references (two distinct objects → false); equals compares content (same text → true).
Worked example
Why is String immutable in Java, and what do you use instead for heavy editing?
- Immutability makes strings safe to share (thread-safe, usable as map keys, cacheable in the pool).
- Any 'change' produces a new String, so repeated concatenation is wasteful.
- Use StringBuilder (or StringBuffer for thread safety) which is mutable and edits in place.
Answer: Immutability brings safety and pooling, but means edits create new objects; use mutable StringBuilder for heavy editing.
⚠ Watch out
- == vs equals is the #1 Java trap — use equals for content, always.
- Integer caching: Integer values -128..127 are cached, so == may be true for small ints but false for large ones — use equals.
- String concatenation in a loop with + is O(n²) garbage; use StringBuilder.