0Pricing
Java Academy · Lesson

String Immutability and the String Pool

Understand why Strings are immutable, how the string pool works, and when to use == vs equals.

String Immutability and the String Pool is a free Java Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

String Immutability and the String Pool

Strings are immutable in Java. Understanding immutability, the string pool, and reference equality vs value equality prevents subtle bugs.

Why Strings are Immutable

String objects cannot be modified after creation. Any operation that "changes" a String actually creates a new String object. This enables sharing, thread-safety, and hashCode caching.

String s = "hello";
s.toUpperCase(); // creates a new String, does NOT modify s
System.out.println(s); // still "hello"

String upper = s.toUpperCase(); // must capture the result
System.out.println(upper); // HELLO

The String Pool (Interning)

String literals are stored in the String Pool (a special section of heap). Two literals with the same content share the same object.

String a = "hello"; // goes into pool
String b = "hello"; // same object from pool
String c = new String("hello"); // forces new object outside pool

System.out.println(a == b);       // true  (same pool reference)
System.out.println(a == c);       // false (different objects)
System.out.println(a.equals(c));  // true  (same content)

== vs equals()

Always use .equals() to compare String content. The == operator checks if two variables point to the same object (reference equality).

String input = new String("admin"); // from user input, not pooled
String role  = "admin";

// Dangerous: fails because different objects
if (input == role) System.out.println("Same"); // not printed!

// Correct: compares content
if (input.equals(role)) System.out.println("Equal!"); // prints

// Null-safe: put constant first to avoid NPE
if ("admin".equals(input)) System.out.println("Admin"); // prints

intern(): Manually Pool a String

String.intern() forces a String into the pool and returns the pooled reference. Rarely needed in modern Java.

String s1 = new String("interned");
String s2 = s1.intern();
String s3 = "interned"; // already in pool

System.out.println(s2 == s3); // true (both point to pool)
System.out.println(s1 == s3); // false (s1 is off-pool)

// Modern use: prefer String.intern() only when you need
// identity-based caching with thousands of repeated strings

String Concatenation Behavior

Concatenation with + creates new String objects. Inside a loop, this is O(n²). The compiler optimizes single expressions but not loop-based concatenation.

// Compiler optimizes this to a StringBuilder automatically:
String result = "Hello, " + "World" + "!";

// In loops: compiler does NOT optimize — use StringBuilder explicitly!
List<String> words = List.of("a", "b", "c", "d");
String bad = ""; // O(n^2) — new object each iteration
for (String w : words) bad += w;

StringBuilder sb = new StringBuilder();
for (String w : words) sb.append(w); // O(n) — efficient
String good = sb.toString();
System.out.println(good); // abcd

Comparing Strings Correctly

Always use equals(); for case-insensitive comparison use equalsIgnoreCase(). compareTo() for lexicographic ordering.

String a = "Java";
String b = "java";

System.out.println(a.equals(b));             // false
System.out.println(a.equalsIgnoreCase(b));   // true
System.out.println(a.compareToIgnoreCase(b)); // 0 (equal)
System.out.println(a.compareTo(b));           // negative (J < j in Unicode)

String Hashcode Caching

Because strings are immutable, Java caches the hashCode after the first call. Subsequent calls return the cached value — making strings very efficient as HashMap keys.

String key = "product:12345";
// hashCode computed once and cached:
int h1 = key.hashCode();
int h2 = key.hashCode(); // returns cached value
System.out.println(h1 == h2); // true

// Strings are ideal HashMap keys because:
// 1. hashCode is consistent (immutable content)
// 2. hashCode is cached (fast repeated lookups)
// 3. equals is well-defined (content-based)
Map<String, Integer> map = new HashMap<>();
map.put("key", 42);
System.out.println(map.get("key")); // 42

String is Final

The String class is final — it cannot be subclassed. This guarantees that no subclass can break immutability or hashCode consistency.

// String is final — this will not compile:
// class MutableString extends String {} // compile error

// You cannot override String behavior.
// If you need custom string-like behavior, use a wrapper:
record ProductSku(String value) {
    ProductSku { if (!value.matches("[A-Z]{3}-[0-9]{4}")) throw new IllegalArgumentException(); }
    @Override public String toString() { return value; }
}

String.format vs Concatenation

For multi-part strings, prefer String.format() or text blocks over concatenation for clarity and easier localization.

String name = "Alice";
int age = 30;
double score = 97.5;

// Concatenation — harder to read with many parts
String bad = "User: " + name + ", Age: " + age + ", Score: " + score;

// String.format — clear placeholders
String good = String.format("User: %s, Age: %d, Score: %.1f", name, age, score);

System.out.println(good);
// User: Alice, Age: 30, Score: 97.5

Null-Safe String Operations

Many String operations throw NPE if the string is null. Use defensive patterns or String.valueOf() to handle null safely.

String value = null;

// Null-safe length check
int len = (value != null) ? value.length() : 0;
System.out.println(len); // 0

// Null-safe comparison (put constant first)
boolean isAdmin = "admin".equals(value); // false, no NPE

// String.valueOf converts null to "null" string
System.out.println(String.valueOf(value)); // "null"
System.out.println(Objects.toString(value, "default")); // "default"

Quick Check

What does the following code print?

String a = "hello";
String b = new String("hello");
System.out.println(a.equals(b));
System.out.println(a == b);

Recap: String Immutability and the String Pool

Key takeaways:

  • Strings are immutable — operations return new String objects, never modify the original
  • String literals are pooled — two literals with same content share one object
  • Always use .equals() to compare String content; == compares object references
  • Use equalsIgnoreCase() for case-insensitive comparisons
  • String concatenation in loops is O(n²) — use StringBuilder for efficiency
  • Strings cache their hashCode — making them efficient and safe as HashMap keys

Frequently asked questions

Is the “String Immutability and the String Pool” lesson free?

Yes — the full text of “String Immutability and the String Pool” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.

What will I learn in “String Immutability and the String Pool”?

Understand why Strings are immutable, how the string pool works, and when to use == vs equals. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Java Academy?

No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “String Immutability and the String Pool” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Java Academy lesson?

Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. String Immutability and the String Pool
  2. StringBuilder for Efficient Concatenation
  3. Text Blocks and String.format
  4. Regular Expressions with Pattern and Matcher
← Back to Java Academy