What is the String Pool in Java

Overview

1. Introduction

In this article, we'll look at two important concepts regarding String in Java: its immutability and how the String pool works.

2. String Immutability

Let's first understand mutability. Objects in Java can be mutable or immutable. A mutable object can be changed without creating an entirely new object. That is the standard behavior of most classes in Java.

One exception for the described behavior is the String class. The String class is an immutable wrapper for sequences of characters. That means we can't change it without creating a new instance of String.

Understanding immutability is vital to design our code in a memory-efficient way because we want to avoid creating unnecessary objects only to change their value.

Let's take a look at one example of immutability in the String class:

1  public static void main(String[] args) {
2    String oneText = "myText";
3    System.out.println(oneText);
4    oneText.concat(" moreText");
5    System.out.println(oneText);
6  }

The code above creates one String called oneText and concatenates the literal moreText to it. Since String is immutable, the concat method doesn't change the original object value to myText moreText but creates a new object. Thus, the oneText variable stays the same. Let's check the output for this code:

1myText
2myText

Both calls to System.out.println outputs the same text. The concat method creates another String, but we don't assign it to a new variable. Expecting to change the original String and not transfer the result to a new variable is a common mistake when designing Java code.

Let's rewrite the code to get the result of concat and set it to a new variable:

1  public static void main(String[] args) {
2    String oneText = "myText";
3    System.out.println(oneText); // outputs myText
4    String anotherText = oneText.concat(" moreText");
5    oneText = oneText.concat(" moreText"); // -> overrides the value of oneText with the concatenation. The old value of oneText = myText is lost in this context
6    System.out.println(anotherText); // outputs myText moreText
7    System.out.println(oneText); // outputs myText moreText
8  }

In the code above, the concat method called from oneText assign the result to another variable anotherText. Thus, anotherText now contains the value myText moreText. We've applied the same idea to the oneText variable, using the = operator to override the old value with the result of concat. Therefore, oneText also contains the value myText anotherText. Let's check out the output for that code.

1myText
2myText moreText
3myText moreText

3. The String Pool

We've made all this introduction to immutability because it is an important concept to understand the String Pool. The JVM takes advantage of the String immutability to optimize the application's memory usage.

The String Pool is located at the memory's heap portion. One purpose is to store String objects created using literals (the double quote notation) and reuse them whenever possible.

3.1. String Literals Reusage

When we create a new String object using a literal value, the JVM searches for that exact String in the Pool and reuses it instead of creating a new object. Since Strings are immutable, their value in memory never changes. The JVM can retrieve the already created value if the stored value is the same as the new object. Let's visualize that using a diagram:

String Pool illustrated

In the above image, you can see that variables a and b were assigned to the same position in the memory because they contain the same value equal to text. String c was given to another position since it holds a different value equal to anotherText.

Let's prove that with the code below:

1  public static void main(String[] args) {
2    String oneText = "myText";
3    String anotherText = "myText";
4    
5   System.out.println(oneText == anotherText); -> true
6  }

We create the variables oneText and anotherText using identical literals. In this case, the JVM finds the value myText in the String Pool before creating a new object. Since the value myText is already in the Pool, the anotherText variable use the same memory reference of oneText. Therefore, both variables should point to the same address, and the code should output true.

3.2. Strings Created using new

String Pool only works for literals (created using double quotes); thus, the String Pool doesn't optimize the retrieval of Strings created using the new keyword. Using that method, the JVM always creates a new object reference and doesn't reuse it even if it finds the same value at the Pool. Therefore, if we run the code below, it should always return false:

1  public static void main(String[] args) {
2    String oneText = "myText";
3    String anotherText = new String("myText");
4    
5    System.out.println(oneText == anotherText);
6  }

4. Thoughts on String Creation

It is a good practice always to create String objects using literals, and here's why:

  1. It makes the code clearer. It's easier to read String a = "text" instead of String a = new String("text").
  2. It opens a window for potential optimizations by the JVM. The String Pool never reuses Strings created using new.

Another thing to keep in mind is that Strings allocated in the String Pool are eligible for garbage collection, just like any other object. Thus, if a literal loses all its references, the JVM erases it from the heap.

5. Conclusion

In this article, we've learned a bit about the String class immutability and how the String Pool stores its objects.