9.4 StringBuilder and Advanced String Handling
1. String Immutability and Performance Issues
String objects are immutable — once created, they never change. The + operator does not modify the existing string; it creates a new String object every time.
// This looks fine but is very inefficient...
String result = "";
for (int i = 0; i < 10000; i++) {
result += i; // ← Creates a new String object every iteration!
}
10,000 iterations = 10,000 objects created and discarded. Wasteful on memory and CPU.
2. StringBuilder: Mutable Strings
StringBuilder holds an internal mutable buffer (char[]), so adding, inserting, or deleting characters does not create new objects.
StringBuilder sb = new StringBuilder();
sb.append("Hello"); // Hello
sb.append(", "); // Hello,
sb.append("Java"); // Hello, Java
sb.append("!"); // Hello, Java!
sb.insert(5, " World"); // Hello World, Java!
sb.delete(5, 11); // Hello, Java!
sb.reverse(); // !avaJ ,olleH
sb.replace(0, 5, "Bye"); // Bye, Java! (after reverse, be careful)
System.out.println(sb.toString()); // Convert to String
System.out.println(sb.length()); // Current length
System.out.println(sb.charAt(0)); // Character at position
Real-World Example: Correct String Joining in Loops
// ✅ StringBuilder (recommended)
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 100; i++) {
sb.append(i);
if (i < 100) sb.append(", ");
}
String csv = sb.toString(); // 1, 2, 3, ..., 100
// ✅ Stream joining (Java 8+)
String result = IntStream.rangeClosed(1, 100)
.mapToObj(String::valueOf)
.collect(Collectors.joining(", "));
Method Chaining
String result = new StringBuilder()
.append("Name: ")
.append("Alice")
.append(", Age: ")
.append(30)
.toString();
3. StringBuilder vs StringBuffer
StringBuilder | StringBuffer | |
|---|---|---|
| Thread-safe | ❌ Not safe | ✅ synchronized |
| Performance | ✅ Faster | Slower |
| When to use | Single-threaded (general use) | Multi-threaded |
Practical tip: In modern Java, use
StringBuilderfor single-threaded use. For multi-threaded shared string access, usejava.util.concurrenttools rather thanStringBuffer.
4. Key String Methods Reference
String s = " Hello, Java World! ";
// Whitespace
s.trim(); // Remove leading/trailing whitespace (ASCII)
s.strip(); // Remove leading/trailing whitespace (Unicode, Java 11+)
s.stripLeading(); // Leading whitespace only
s.stripTrailing(); // Trailing whitespace only
s.isBlank(); // true if only whitespace (Java 11+)
// Case
"Hello".toUpperCase(); // HELLO
"Hello".toLowerCase(); // hello
// Search
"Hello Java".contains("Java"); // true
"Hello Java".startsWith("Hello"); // true
"Hello Java".endsWith("Java"); // true
"Hello Java".indexOf("a"); // 7
"Hello Java".lastIndexOf("a"); // 9
// Extraction
"Hello Java".substring(6); // "Java"
"Hello Java".substring(0, 5); // "Hello"
"Hello Java".charAt(0); // 'H'
// Replacement
"Hello Java".replace("Java", "World"); // "Hello World"
"Hello Java".replaceAll("\\s+", "_"); // "Hello_Java" (regex)
// Comparison
"hello".equals("HELLO"); // false
"hello".equalsIgnoreCase("HELLO"); // true
"abc".compareTo("abd"); // negative (lexicographic)
// Java 11+
"Java\n".repeat(3); // "Java\n" repeated 3 times
// Java 15+
"Name: %s, Age: %d".formatted("Alice", 30); // "Name: Alice, Age: 30"
5. Text Formatting Options
String name = "Alice";
double gpa = 3.75;
// String.format (traditional)
String s1 = String.format("Name: %s, GPA: %.2f", name, gpa);
// formatted() (Java 15+, more readable)
String s2 = "Name: %s, GPA: %.2f".formatted(name, gpa);
// Text Block + formatted (multi-line)
String json = """
{
"name": "%s",
"gpa": %.2f
}
""".formatted(name, gpa);
JVM String + optimization: The compiler automatically folds "a" + "b" + "c" into "abc" at compile time for constants. Also, Java 9+ converts simple + outside loops into StringBuilder. However, += inside loops is NOT automatically optimized — always use StringBuilder directly in loops.