Comprehensive Comparison Table
| Feature | String 📜 | StringBuilder ⚡ | StringBuffer 🔒 |
| Mutability 🔄 | Immutable | Mutable | Mutable |
| Thread Safety 🛡️ | Thread-safe (immutable) | ❌ Not thread-safe | ✅ Thread-safe (synchronized) |
| Performance 🏎️ | ❌ Slow for concatenations | ✅ Fast | Moderate (slower than StringBuilder) |
| Memory Usage 💾 | ❌ High for multiple operations | ✅ Low | ✅ Low |
| Package 📦 | java.lang | java.lang | java.lang |
| Introduced 📅 | JDK 1.0 | JDK 1.5 | JDK 1.0 |
| Synchronization ⚙️ | N/A | No synchronization | ✅ Synchronized methods |
| Best Use Case 🎯 | Constants, simple operations | Single-threaded string building | Multi-threaded string building |
Detailed Feature Comparison
| Aspect | String | StringBuilder | StringBuffer |
| Creation Speed 🚀 | Fast | Fast | Fast |
| Concatenation Speed 🔗 | Very Slow (O(n²)) | ✅ Very Fast (O(1) amortized) | Fast (O(1) amortized) |
| Memory Overhead 📊 | High (creates new objects) | Low (reuses buffer) | Low (reuses buffer) |
| Buffer Management 🗂️ | N/A | ✅ Automatic resize | ✅ Automatic resize |
| Initial Capacity 📏 | N/A | 16 characters | 16 characters |
| Capacity Growth 📈 | N/A | (old capacity × 2) + 2 | (old capacity × 2) + 2 |
Method Availability
| Method Category | String | StringBuilder | StringBuffer |
| Append Operations ➕ | ❌ (creates new objects) | ✅ append() | ✅ append() |
| Insert Operations 📝 | ❌ | ✅ insert() | ✅ insert() |
| Delete Operations 🗑️ | ❌ | ✅ delete(), deleteCharAt() | ✅ delete(), deleteCharAt() |
| Replace Operations 🔄 | ✅ replace() (new object) | ✅ replace() (modifies) | ✅ replace() (modifies) |
| Reverse Operation ↩️ | ❌ | ✅ reverse() | ✅ reverse() |
| Capacity Management 📦 | ❌ | ✅ capacity(), ensureCapacity() | ✅ capacity(), ensureCapacity() |
| String Conversion 🔄 | N/A (already String) | ✅ toString() | ✅ toString() |
Thread Safety Details
| Scenario | String | StringBuilder | StringBuffer |
| Single Thread 🧵 | ✅ Safe | ✅ Optimal choice | ✅ Safe but overkill |
| Multiple Threads Reading 👥📖 | ✅ Safe | ⚠️ Safe if no modifications | ⚠️ Safe if no modifications |
| Multiple Threads Writing 👥✍️ | ✅ Safe (immutable) | ❌ Race conditions | ✅ Safe (synchronized) |
| Performance in Multithreading 🏁 | Good | N/A (unsafe) | Moderate (lock overhead) |
| Operation | String Memory Impact | StringBuilder Memory Impact | StringBuffer Memory Impact |
| 1000 Concatenations | ~500MB (1000 objects) | ~16KB (1 buffer) | ~16KB (1 buffer) |
| Empty Creation | ~40 bytes | ~56 bytes | ~72 bytes (sync overhead) |
| With 50 chars | ~140 bytes | ~156 bytes | ~172 bytes |
| Class | Time (ms) | Memory Objects Created | Relative Performance |
| String | ~500ms | 10,000 | 1x (baseline) |
| StringBuilder | ~1ms | 1 | 500x faster |
| StringBuffer | ~3ms | 1 | 167x faster |
| Scenario | StringBuilder | StringBuffer | Performance Difference |
| Single Thread | 1ms | 3ms | StringBuilder 3x faster |
| 2 Threads | Unsafe | 5ms | N/A |
| 4 Threads | Unsafe | 8ms | N/A |
| 8 Threads | Unsafe | 15ms | N/A |
Code Examples Comparison
Basic Usage
String str = "Hello";
str = str + " World";
str = str + "!";
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
sb.append("!");
String result = sb.toString();
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" World");
buffer.append("!");
String result2 = buffer.toString();
Multi-threading Examples
public class UnsafeExample {
private StringBuilder sb = new StringBuilder();
public void appendText(String text) {
sb.append(text);
}
}
public class SafeExample {
private StringBuffer buffer = new StringBuffer();
public void appendText(String text) {
buffer.append(text);
}
}
public class ManualSyncExample {
private StringBuilder sb = new StringBuilder();
private final Object lock = new Object();
public void appendText(String text) {
synchronized(lock) {
sb.append(text);
}
}
}
When to Use Each
Use String When 📜
- Constants and literals
- Simple concatenations (1-2 operations)
- Immutable data requirements
- API parameters and return values
- Thread safety without performance concerns
public static final String ERROR_MSG = "Error occurred";
String name = firstName + " " + lastName;
String filePath = directory + "/" + filename;
Use StringBuilder When ⚡
- Multiple concatenations
- Single-threaded environments
- Performance is critical
- Building large strings dynamically
- Most common choice for string building
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM users WHERE ");
for (String condition : conditions) {
sql.append(condition).append(" AND ");
}
Use StringBuffer When 🔒
- Multi-threaded string building
- Legacy code compatibility
- Thread safety is mandatory
- Concurrent access to shared string builder
public class LogBuffer {
private StringBuffer buffer = new StringBuffer();
public synchronized void addLog(String message) {
buffer.append(new Date()).append(": ").append(message).append("\n");
}
public synchronized String getLogs() {
return buffer.toString();
}
}
Migration Guidelines
String → StringBuilder
String result = "";
for (String item : items) {
result += item + ", ";
}
StringBuilder sb = new StringBuilder();
for (String item : items) {
sb.append(item).append(", ");
}
String result = sb.toString();
StringBuffer → StringBuilder
StringBuffer buffer = new StringBuffer();
buffer.append("text");
StringBuilder sb = new StringBuilder();
synchronized(lock) {
sb.append("text");
}
Best Practices Summary
| Practice | String | StringBuilder | StringBuffer |
| Default Choice | Simple operations | Complex string building | Multi-threaded building |
| Capacity Setting | N/A | Set initial capacity | Set initial capacity |
| Reuse | Create new | Clear and reuse | Clear and reuse |
| Thread Safety | Inherent | Manual if needed | Automatic |
| Performance | Accept for simple ops | Optimize for complex | Accept sync overhead |
Conclusion
- String: Choose for simplicity and immutability requirements
- StringBuilder: Choose for performance in single-threaded scenarios (most common)
- StringBuffer: Choose only when thread safety is required
In modern Java development, StringBuilder is the go-to choice for string building operations, with StringBuffer reserved for specific multi-threading needs.