Sitemap
CodeBook

CodeBook

Important Insights from various Software Engineer Books- System Design, Databases, Cloud Computing, Web Development Stack

Understanding String Immutability in Java

4 min readOct 6, 2024

--

In Java, a string is considered immutable, meaning its value cannot be changed after creation. This might seem counterintuitive, especially when you append or concatenate strings. Let’s break down what actually happens.

The String Constant Pool

When you create a string literal, Java stores it in a special area of memory called the String Constant Pool. This pool is designed to optimize memory usage by storing identical strings only once. If you create multiple strings with the same value, they will all point to the same object in the pool.

String s1 = "Java";
String s2 = "Java";

When we create these two strings, we might initially think that two separate objects are being created in memory. However, due to Java’s string interning mechanism, only one object is actually created.

String Interning:

  • String Constant Pool: Java maintains a String Constant Pool in the heap memory. This pool stores unique string literals.
  • Object Reuse: When a string literal is encountered, the JVM checks if it already exists in the pool. If it does, it reuses the existing object. If not, it creates a new object and adds it to the pool.

In the given example:

  1. The first string s1 = "Java" is created and added to the String Constant Pool.
  2. When the second string s2 = "Java" is created, the JVM finds that "Java" already exists in the pool and reuses the same object.

Both s1 and s2 are references to the same string object in the String Constant Pool. Therefore, comparing them using == will result in true, as they point to the same memory location.

String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); // returns true

Concatenation and New Objects

When you concatenate strings, Java doesn’t modify the existing strings. Instead, it creates a new string that is the combination of the original strings. This new string is then stored in the String Constant Pool.

String str = "Hello";
str += " World";
System.out.println(str); // Creates a new string "Hello World"

In this code, we’re initially creating a string str with the value "Hello". When we concatenate " World" to it, we're not modifying the original "Hello" string. Instead, Java creates a new string, "Hello World," and assigns it to the str variable.

Get CodeBook’s stories in your inbox

Join Medium for free to get updates from this writer.

Why is this happening?

  1. String Constant Pool: As discussed earlier, strings are stored in the String Constant Pool, a special area in the heap. This pool ensures that identical strings are only stored once, improving memory efficiency.
  2. New Object Creation: When you concatenate strings, Java creates a new string object in the String Constant Pool. This new object contains the combined content of the original strings.
  3. Reassignment: The str variable is then reassigned to reference this new string object. The original "Hello" string remains unchanged in the pool. And if “Hello” string no longer referenced by any active part of the program, it will eventually reclaimed by the garbage collector.

Visualizing the Process:

Before concatenation:
- str: "Hello" (points to the "Hello" string in the String Constant Pool)

After concatenation:
- str: "Hello World" (points to the newly created "Hello World" string in the String Constant Pool)

Mutable Alternatives: StringBuilder and StringBuffer

If you need to modify strings frequently, you can use the StringBuilder or StringBuffer classes. These classes are mutable, meaning you can change their contents without creating new objects.

StringBuilder vs. StringBuffer: A Closer Look

Both StringBuilder and StringBuffer classes in Java are designed for efficient mutable string manipulation. However, they differ in their underlying implementation and thread safety.

Thread Safety:

  • StringBuffer: Synchronized methods are used in StringBuffer to ensure thread safety. This means that multiple threads can safely modify the same StringBuffer object without causing data corruption. However, synchronization comes at the cost of performance.
  • StringBuilder: StringBuilder is not synchronized. It is faster than StringBuffer because it avoids the overhead of synchronization. However, it is not thread-safe. If multiple threads need to modify the same StringBuilder object, explicit synchronization must be implemented.
// StringBuilder (not thread-safe)
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString()); // Output: Hello World

// StringBuffer (thread-safe)
StringBuffer sb2 = new StringBuffer("Hello");
sb2.append(" World");
System.out.println(sb2.toString()); // Output: Hello World

Use Cases:

  • StringBuffer: Use StringBuffer when thread safety is a concern. For example, if multiple threads are concurrently modifying a string, StringBuffer can prevent race conditions.
  • StringBuilder: Use StringBuilder when thread safety is not required and performance is a priority. For example, in single-threaded applications or when modifications are performed within a synchronized block.

Practical Considerations

Concatenation Performance

While immutability is generally efficient, excessive string concatenation can lead to performance issues due to the creation of multiple new objects. In such cases, consider using StringBuilder or StringBuffer for more efficient mutable string operations.

String Comparison

When comparing strings for equality, use the equals() method instead of the == operator. The == operator compares references, while equals() compares the actual string content.

--

--

Written by CodeBook

Important Insights from various Software Engineer Books- System Design, Databases, Cloud Computing, Web Development Stack