Java provides three classes for working with character sequences: immutable String, thread-safe mutable StringBuffer, and non-thread-safe mutable StringBuilder. Understanding when to use each is critical for writing correct and performant code.
The tradeoff is between safety and performance. Immutability (String) is the safest but creates garbage under modification. Synchronization (StringBuffer) adds thread safety but incurs overhead. StringBuilder drops synchronization for speed but is unsafe in shared contexts.
| Dimension | String | StringBuffer | StringBuilder |
|---|---|---|---|
| Mutability | Immutable | Mutable | Mutable |
| Thread safety | Safe (immutable) | Safe (synchronized) | Unsafe |
| Performance | Slow for modification | Moderate (sync overhead) | Fastest |
| Use case | Fixed text, constants, keys | Legacy code (Java 1.0) | Dynamic building (Java 1.5+) |
| Concatenation in loops | O(n²) garbage | O(n) buffer | O(n) buffer |
- The value never changes after creation
- As map keys (immutability guarantees hash stability)
- Thread-safe sharing without synchronization
- Short, fixed strings
- Building strings dynamically in a single-threaded context
- Inside methods (local variable, no sharing)
- String concatenation in loops (compiler translates
+to StringBuilder anyway)
- Mutable string building in a shared, multi-threaded context
- Legacy code that already uses it
- Rare —
StringBuilderis almost always preferred in modern code
The Java compiler itself prefers StringBuilder — "a" + "b" + "c" is compiled to new StringBuilder().append("a").append("b").append("c").toString(). There is almost never a reason to use StringBuffer in new code. The real choice is between String (immutable, safe) and StringBuilder (mutable, fast).
- Java Strings — the immutable baseline for comparison
- StringBuilder and StringBuffer — the mutable alternatives
- Java Memory Management — immutability enables string pooling
- Java Synchronization — StringBuffer’s synchronized methods explained