String Immutability

Why strings are immutable in Java

Interview Relevant: Critical concept for interviews
6 min read

Understanding String Immutability

In Java, strings are immutable - once a String object is created, its content cannot be changed. Any operation that appears to modify a string actually creates a new String object.

What Does Immutable Mean?

  • The internal char array cannot be modified
  • Methods like toUpperCase() return NEW strings
  • Concatenation creates NEW objects
  • The original string remains unchanged

āœ“ Why Immutable?

  • Security: Strings used in network, file paths, database queries can't be changed
  • Thread Safety: Can be shared between threads without synchronization
  • Caching: Enables String Pool for memory optimization
  • Hashcode Caching: Hash can be cached since content never changes

āš ļø Performance Impact: String concatenation in loops creates many temporary objects. Use StringBuilder for better performance!

Code Examples

String operations create new objects

java
1// Demonstrating immutability
2String original = "Hello";
3
4// These operations create NEW strings
5String upper = original.toUpperCase();
6String replaced = original.replace('H', 'J');
7String concatenated = original + " World";
8
9// Original is UNCHANGED
10System.out.println(original);      // "Hello" (unchanged!)
11System.out.println(upper);         // "HELLO" (new object)
12System.out.println(replaced);      // "Jello" (new object)
13System.out.println(concatenated);  // "Hello World" (new object)
14
15// Visual memory representation:
16// original → "Hello"
17// upper → "HELLO"
18// replaced → "Jello"
19// concatenated → "Hello World"

Security and HashMap benefits

java
1// Why immutability matters for security
2public void connectToDatabase(String connectionString) {
3    // If strings were mutable, this could be changed!
4    // connectionString could be modified after validation
5    validateConnectionString(connectionString);
6    
7    // Because strings are immutable, connectionString
8    // cannot be changed between validation and use
9    establishConnection(connectionString);
10}
11
12// Safe to use as HashMap keys
13Map<String, Integer> map = new HashMap<>();
14String key = "myKey";
15map.put(key, 42);
16
17// Even if someone has a reference to 'key',
18// they cannot modify it and break the map
19// key.modify();  // Not possible!
20
21System.out.println(map.get("myKey"));  // 42 (always works!)

Performance implications and solutions

java
1// Performance problem: String concatenation in loops
2// BAD - Creates many intermediate String objects!
3String result = "";
4for (int i = 0; i < 10000; i++) {
5    result += i;  // Creates new String each iteration!
6}
7// This creates ~10000 temporary String objects!
8
9// GOOD - Use StringBuilder
10StringBuilder sb = new StringBuilder();
11for (int i = 0; i < 10000; i++) {
12    sb.append(i);  // Modifies same object
13}
14String result2 = sb.toString();
15
16// Performance comparison:
17// Bad approach: O(n²) time, many objects
18// Good approach: O(n) time, one StringBuilder
19
20// Modern approach: String.join or Stream
21String numbers = IntStream.range(0, 10000)
22    .mapToObj(String::valueOf)
23    .collect(Collectors.joining());

Hashcode caching and thread safety

java
1// Hash code caching due to immutability
2String str = "Hello";
3
4// First call calculates and caches hash
5int hash1 = str.hashCode();
6
7// Subsequent calls return cached value (faster!)
8int hash2 = str.hashCode();  // No recalculation
9
10System.out.println(hash1 == hash2);  // true
11
12// This is why Strings are excellent HashMap keys:
13// 1. Hash never changes
14// 2. Can be cached for performance
15
16// Thread safety from immutability
17String sharedString = "Shared Data";
18
19// Multiple threads can read without synchronization
20Thread t1 = new Thread(() -> System.out.println(sharedString));
21Thread t2 = new Thread(() -> System.out.println(sharedString));
22// No risk of data corruption!
23
24// Contrast with mutable StringBuilder:
25StringBuilder mutable = new StringBuilder("Data");
26// Concurrent access would require synchronization

Use Cases

  • Security-sensitive operations (passwords, URLs)
  • Multi-threaded applications
  • HashMap/HashSet keys
  • API design with stable contracts
  • Caching and interning
  • Configuration values

Common Mistakes to Avoid

  • Expecting string methods to modify original
  • String concatenation in loops
  • Not understanding memory implications
  • Assuming reassignment modifies the string
  • Not leveraging thread safety benefits
  • Using String when StringBuilder is better