Why String Is Immutable in Java — Security, Hashing, the String Pool, and Thread Safety
Fast recall
Quick revision
Core answer
String is immutable for four intertwined reasons: (1) Security — strings used as file paths, URLs, class names, and credentials can be passed between trust boundaries knowing no caller can mutate them later; (2) Hash caching — String caches its hashCode() on first call; mutation would silently break every HashMap and HashSet entry; (3) String pool / interning — the JVM interns string literals to save memory and relies on immutability to share instances safely; (4) Thread safety — immutable objects are inherently thread-safe, no synchronization needed. The trade-off is modification cost — s = s + "x" allocates a new String — so use StringBuilder for heavy concatenation and Java 9+ compact strings reduce the memory overhead.Whether the candidate can explain the four interconnected reasons and understand the trade-offs (modification cost vs safety benefits)
Giving only one reason (usually thread-safety). Not knowing that hashCode caching is why HashMap keys must be immutable. Confusing `String` literals with `new String()`
Mention Java 9+ compact strings (byte[] with encoding flag) reducing memory, the `StringConcatFactory` (Java 9+) for concatenation, and that records and value types (Project Valhalla) continue this design philosophy
Interview-ready guide
Interview answer
Immutability of String is one of Java's foundational design decisions — it's not just a default; it's there for four interconnected reasons.
Security
- Strings flow across trust boundaries as file paths, URLs, class names, credentials
- If mutable, a caller could validate a safe path and another thread could rewrite it before the actual filesystem call — a TOCTOU race
ClassLoader.loadClass,Class.forName,File,URL, SSL — all rely on strings being immutable to remain secure
Hash caching
String.hashCode()is computed once and cached internally- Every
HashMap.get("key")uses the cached hash — near-free after the first call - If strings were mutable, cached hashes would point to old buckets; entries would silently disappear
- This is why mutable objects shouldn't be map keys in general
String pool
- The JVM interns string literals:
"hello" == "hello"from two different places is the same object - Saves significant memory (50KB–tens of MB depending on app)
- Sharing is only safe because strings are immutable — otherwise one caller mutating the pooled instance corrupts everyone
Thread safety
- Immutable objects are inherently thread-safe — no locks, no volatile, no memory barriers
- You can pass a
Stringbetween threads with zero synchronization overhead - Contrast with
StringBuilder, which is not thread-safe;StringBufferexists only becauseStringavoided that synchronization cost
Cost and modern mitigations
- Every modification creates a new object — naive
+=in a loop is O(n²) StringBuilderfor heavy concatenation,StringBufferfor the rare thread-safe case- Java 9+ compact strings use
byte[]internally with a Latin-1 flag — half the memory for English text - Java 9+
StringConcatFactorylets the JVM pick the fastest+strategy at runtime viainvokedynamic
Recommendation: Treat String immutability as a feature, not a limitation. Use StringBuilder in loops and any heavy text construction, but rely on String everywhere else — the hash caching, interning, and thread safety payoffs show up in almost every Java application. And remember: the same reasoning argues for making your own value types immutable — records and value classes (Project Valhalla) extend this philosophy to user code.
Why `String` Is Immutable in Java — Security, Hashing, the String Pool, and Thread Safety
Direct Answer
String is immutable for four intertwined reasons: (1) Security — strings used as file paths, URLs, class names, and credentials can be passed between trust boundaries knowing no caller can mutate them later; (2) Hash caching — String caches its hashCode() on first call; mutation would silently break every HashMap and HashSet entry; (3) String pool / interning — the JVM interns string literals to save memory and relies on immutability to share instances safely; (4) Thread safety — immutable objects are inherently thread-safe, no synchronization needed. The trade-off is modification cost — s = s + "x" allocates a new String — so use StringBuilder for heavy concatenation and Java 9+ compact strings reduce the memory overhead.
Common Mistakes & Pitfalls
Giving only one reason (usually thread-safety). Not knowing that hashCode caching is why HashMap keys must be immutable. Confusing String literals with new String()
Check your understanding
Answer these without looking back at the article.
- How does Java 9's compact string feature work, and when does it fall back to UTF-16?
- Why does `new String("hello")` create a new object while `String s = "hello"` uses the pool?
- What does `String.intern()` do, and when should you use it explicitly?
- Why is caching `hashCode()` safe in `String` but not in a mutable object?
- How did `StringConcatFactory` in Java 9+ change how `+` concatenation is compiled?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.