String Pool in Java

Learn how Java saves memory by reusing Strings

Think of String Pool like a toy library! Instead of every kid buying the same toy, they all share toys from the library. Java does the same with Strings - it keeps one copy and lets everyone share it to save memory!

What is the String Pool?

The String Pool (or String Intern Pool) is a special memory area in Java where String literals are stored. When you create a String literal, Java checks if it already exists in the pool. If it does, Java reuses it instead of creating a new one!

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Creating String literals
String str1 = "Hello"; // Creates "Hello" in String Pool
String str2 = "Hello"; // Reuses "Hello" from pool (no new object!)
String str3 = "Hello"; // Reuses again!
// All three point to the SAME object in memory!
System.out.println(str1 == str2); // true (same memory address)
System.out.println(str2 == str3); // true (same memory address)
// Visual representation:
// String Pool: ["Hello"]
// ↑ ↑ ↑
// str1 str2 str3 (all pointing to same "Hello"!)
// Result: Only 1 "Hello" object created instead of 3!
// Memory saved: 66%!

String Literals vs new String()

There are two ways to create Strings in Java, and they work very differently:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Method 1: String Literal (RECOMMENDED)
String literal1 = "Java"; // Stored in String Pool
String literal2 = "Java"; // Reuses from String Pool
System.out.println(literal1 == literal2); // true (same object!)
// Method 2: Using 'new' keyword (NOT RECOMMENDED)
String obj1 = new String("Java"); // Creates NEW object in Heap
String obj2 = new String("Java"); // Creates ANOTHER new object
System.out.println(obj1 == obj2); // false (different objects!)
// Comparing literal with 'new' String
String literal = "Java";
String object = new String("Java");
System.out.println(literal == object); // false (different memory)
System.out.println(literal.equals(object)); // true (same content!)
// Memory visualization:
// String Pool: ["Java"] ← literal1, literal2 point here
// Heap: ["Java"], ["Java"] ← obj1, obj2 point here
//
// Result: Using 'new' creates EXTRA objects!

How Does String Pool Work?

When you create a String literal, Java follows these steps:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Step-by-step String Pool process:
// Step 1: Create first String literal
String s1 = "Cat";
// Java checks String Pool... "Cat" not found
// Java adds "Cat" to pool
// s1 points to "Cat" in pool
// Step 2: Create second String literal
String s2 = "Dog";
// Java checks String Pool... "Dog" not found
// Java adds "Dog" to pool
// s2 points to "Dog" in pool
// Step 3: Create third String literal
String s3 = "Cat";
// Java checks String Pool... "Cat" FOUND!
// Java reuses existing "Cat"
// s3 points to SAME "Cat" as s1
// Step 4: Verification
System.out.println(s1 == s3); // true (same "Cat" object)
System.out.println(s1 == s2); // false (different objects)
// Current String Pool state:
// Pool: ["Cat", "Dog"]
// ↑ ↑ ↑
// s1 s3 s2
// Summary:
// 1. Check if String exists in pool
// 2. If exists: Reuse it
// 3. If not: Create new one and add to pool

The intern() Method

The intern() method lets you manually add Strings to the pool. It returns the pooled version of the String.

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Creating String with 'new' (NOT in pool)
String s1 = new String("Welcome"); // Creates object in Heap (not pool)
String s2 = "Welcome"; // Creates/uses "Welcome" in pool
System.out.println(s1 == s2); // false (different locations!)
// Using intern() to add to pool
String s3 = s1.intern(); // Adds "Welcome" to pool and returns reference
System.out.println(s2 == s3); // true (both point to pool!)
System.out.println(s1 == s3); // false (s1 still points to Heap)
// Real-world example: User input
Scanner scanner = new Scanner(System.in);
System.out.println("Enter country name:");
String userInput = scanner.nextLine(); // NOT in pool (user input)
// Add to pool if it will be used many times
String internedCountry = userInput.intern();
// Now it can be shared!
String country1 = "USA";
String country2 = userInput.intern();
if (userInput.equals("USA")) {
System.out.println(country1 == country2); // true!
}
// When to use intern():
// ✓ Strings used many times (like configuration values)
// ✓ Strings from external sources (files, databases, user input)
// ✗ Strings used only once (waste of performance)
// ✗ Very large Strings (can fill up memory)

Memory Comparison

Let's see how much memory we can save using the String Pool:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Scenario: Creating 1000 "Error" Strings
// BAD: Without String Pool
String[] errors1 = new String[1000];
for (int i = 0; i < 1000; i++) {
errors1[i] = new String("Error"); // Creates 1000 separate objects!
}
// Memory used: 1000 String objects
// Each String object uses ~40 bytes (on 64-bit JVM)
// Total: ~40,000 bytes (40 KB)
// GOOD: With String Pool
String[] errors2 = new String[1000];
for (int i = 0; i < 1000; i++) {
errors2[i] = "Error"; // Reuses same object!
}
// Memory used: 1 String object + 1000 references
// 1 String: ~40 bytes
// 1000 references: ~8000 bytes (8 bytes each on 64-bit)
// Total: ~8,040 bytes (8 KB)
// Memory Saved: 40 KB - 8 KB = 32 KB (80% reduction!)
// Real-world impact:
// If your app has 1 million status messages ("SUCCESS", "FAILED", "PENDING")
// Without pool: 40 MB
// With pool: 8 MB
// Savings: 32 MB! (Plus faster garbage collection!)
System.out.println("Memory saved: " + ((40000 - 8040) * 100 / 40000) + "%");
// Output: Memory saved: 79%

Real-World Example

In a large application, you might have thousands of repeated Strings:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Example: Web Application with repeated strings
class WebApplication {
public static void main(String[] args) {
// Common HTTP status messages (appear thousands of times)
String status1 = "200 OK"; // Added to pool
String status2 = "404 Not Found"; // Added to pool
String status3 = "500 Server Error"; // Added to pool
// Simulating 10,000 HTTP requests
String[] requestLogs = new String[10000];
for (int i = 0; i < 10000; i++) {
int random = (int)(Math.random() * 3);
if (random == 0) {
requestLogs[i] = "200 OK"; // Reuses from pool!
} else if (random == 1) {
requestLogs[i] = "404 Not Found"; // Reuses from pool!
} else {
requestLogs[i] = "500 Server Error"; // Reuses from pool!
}
}
// Result: Only 3 String objects created for 10,000 requests!
// Without pool: Would need 10,000 objects
// Memory saved: 99.97%!
// Checking if they're the same object
System.out.println(requestLogs[0] == requestLogs[100]); // true
System.out.println(requestLogs[500] == requestLogs[5000]); // true
// More examples where String Pool helps:
// 1. Configuration values: "development", "production", "test"
// 2. Error messages: "Invalid input", "Connection failed"
// 3. Button labels: "OK", "Cancel", "Submit"
// 4. Country codes: "US", "UK", "TR"
// 5. File extensions: ".txt", ".pdf", ".jpg"
System.out.println("String Pool saves MASSIVE amounts of memory!");
}
}
// Pro tip: This is why you should use String literals
// instead of new String() whenever possible!

Key Concepts

String Pool Location

The String Pool is stored in the Heap memory (in Java 7+). Before Java 7, it was in PermGen space.

Automatic Pooling

String literals are automatically added to the pool. Strings created with 'new' are not.

Memory Efficiency

Reusing Strings saves a lot of memory, especially for repeated text like error messages, labels, etc.

== vs equals()

Use == to check if two references point to the same object in memory. Use equals() to check if content is the same.

Best Practices

  • Use String literals (not 'new String()') whenever possible
  • Use intern() for Strings that appear many times in your application
  • Be careful with intern() - it can slow down your program if overused
  • Use equals() to compare String content, not ==
  • Understand that String Pool helps with memory, not performance

Common Mistakes

Using == to compare String content

Why it's wrong: == compares memory addresses, not content. Always use equals()!

Creating Strings with new unnecessarily

Why it's wrong: This bypasses the String Pool and wastes memory.

Overusing intern()

Why it's wrong: intern() has a performance cost. Only use it for frequently repeated Strings.

Thinking String Pool makes code faster

Why it's wrong: String Pool saves memory, but doesn't necessarily make your code run faster.

Interview Tips

  • 💡Explain the difference between String literals and new String()
  • 💡Know where the String Pool is located (Heap since Java 7)
  • 💡Understand when to use intern() method
  • 💡Explain how String Pool saves memory
  • 💡Be ready to explain == vs equals() for Strings
  • 💡Know that Strings are immutable, which makes pooling safe