Master Java's text manipulation powerhouse through memory diagrams, performance optimizations, and real-world text processing scenarios
By the end of this lesson, you will:
<aside> š
String Philosophy
Strings in Java are like books in a library - once published (created), they cannot be modified. Any "changes" create new books (new String objects). StringBuilder is like a draft manuscript where you can edit freely before publishing!
</aside>
Java String Memory Management - The Library System
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š String Pool (Method Area) šļø Heap Memory
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā SHARED LIBRARY ā ā INDIVIDUAL COPIES ā
ā ā ā ā
ā "Hello" āāāāāāā¬āāāāāā ā ā String obj1 = new String(...)ā
ā "World" āāāāā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā "Java" āāā ā ā ā ā ā ā String Object āā
ā ā ā ā ā ā ā ā value: "Hello" āā
āāāāāāāāāāāāā¼āā¼āā¼āāāāāā¼āāāāāāāāāāāāāāā ā ā (references pool if intern)āā
ā ā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāā ā ā ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā āāāāāāā ā ā
ā ā ā ā
ā¼ ā¼ ā¼ ā¼
Stack Memory (Local Variables)
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā String s1 = "Hello"; āāāāāāāāāāāāāāāāāāāāāŗ String Pool
ā String s2 = "Hello"; āāāāāāāāāāāāāāāāāāāāāŗ Same Reference!
ā String s3 = new String("Hello"); āāāāāāāŗ Heap Object
ā String s4 = s3.intern(); āāāāāāāāāāāāāāŗ Back to Pool!
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
<aside> š
Immutability Benefits
String immutability enables thread safety, caching optimization, and security - once created, a String cannot be maliciously modified, making it perfect for sensitive data like passwords and URLs.
</aside>
public class DocumentManagementSystem {
// š Demonstrating String immutability in document processing
public void processDocument(String originalContent) {
System.out.println("š Processing document with content: " + originalContent.substring(0, 50) + "...");
// š Every "modification" creates a new String object
String step1 = originalContent.toUpperCase(); // New String object
String step2 = step1.replace("OLD", "NEW"); // Another new String
String step3 = step2.trim(); // Yet another new String
String step4 = step3.concat(" [PROCESSED]"); // And another one!
// š Original string remains unchanged - immutability in action!
System.out.println("Original: " + originalContent.equals(originalContent)); // Always true
System.out.println("Final result: " + step4);
// š Demonstrating object identity vs content equality
demonstrateStringComparison();
}
private void demonstrateStringComparison() {
// š String Pool magic
String literal1 = "Java Programming";
String literal2 = "Java Programming";
String constructed = new String("Java Programming");
String interned = constructed.intern();
System.out.println("\\nš String Comparison Analysis:");
// Reference equality (same object in memory?)
System.out.println("literal1 == literal2: " + (literal1 == literal2)); // true
System.out.println("literal1 == constructed: " + (literal1 == constructed)); // false
System.out.println("literal1 == interned: " + (literal1 == interned)); // true
// Content equality (same characters?)
System.out.println("literal1.equals(constructed): " + literal1.equals(constructed)); // true
System.out.println("literal1.equals(interned): " + literal1.equals(interned)); // true
// šÆ Practical implications for document versioning
trackDocumentVersions(literal1, constructed, interned);
}
private void trackDocumentVersions(String version1, String version2, String version3) {
System.out.println("\\nš Document Version Tracking:");
// Using HashMap to track document versions
Map<String, String> documentVersions = new HashMap<>();
// Since Strings are immutable and have proper hashCode/equals,
// they work perfectly as Map keys
documentVersions.put(version1, "Version from string pool");
documentVersions.put(version2, "Version from new constructor");
documentVersions.put(version3, "Version from intern() method");
System.out.println("Map size: " + documentVersions.size()); // Only 1 entry!
System.out.println("All versions have same content, so Map treats them as same key");
// This demonstrates why String immutability is crucial for data structures
System.out.println("Retrieved value: " + documentVersions.get("Java Programming"));
}
// š Performance impact demonstration
public void demonstratePerformanceImpact() {
System.out.println("\\nā±ļø String Concatenation Performance Test:");
// ā INEFFICIENT: String concatenation in loop
long startTime = System.nanoTime();
String result = "";
for (int i = 0; i < 1000; i++) {
result += "Line " + i + "\\n"; // Creates 2000+ String objects!
}
long inefficientTime = System.nanoTime() - startTime;
// ā
EFFICIENT: StringBuilder for multiple concatenations
startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("Line ").append(i).append("\\n"); // Modifies existing buffer
}
String efficientResult = sb.toString();
long efficientTime = System.nanoTime() - startTime;
System.out.println("Inefficient approach: " + (inefficientTime / 1_000_000) + " ms");
System.out.println("Efficient approach: " + (efficientTime / 1_000_000) + " ms");
System.out.println("Performance improvement: " + (inefficientTime / efficientTime) + "x faster");
// Both results are identical, but performance difference is massive
System.out.println("Results identical: " + result.equals(efficientResult));
}
}