Memra

Immutable Strings & StringBuilder

Why String is immutable, the string pool, == vs equals, and building text the right way.

Strings are immutable

A String in Java is immutable: once a String object exists, its characters never change. Every method that *looks* like it edits a string — concat, replace, toUpperCase, trim, substring, even + — actually returns a brand-new String and leaves the original untouched.

String s = "hello";
s.toUpperCase();          // returns "HELLO" — but we threw it away
System.out.println(s);    // hello   (s is unchanged)

s = s.toUpperCase();      // now we keep the new object
System.out.println(s);    // HELLO

Immutability is why strings are safe to share, safe to use as HashMap keys, and safe across threads.

The string pool and interning

String literals are *interned*: the JVM keeps one shared pool of literal strings, so two identical literals are the same object. But a string built at runtime (with new or by concatenating variables) is a fresh object on the heap.

String a = "java";
String b = "java";
String c = new String("java");

a == b          // true  — both refer to the one pooled literal
a == c          // false — c is a distinct new object
a.equals(c)     // true  — same characters

== compares references; .equals compares contents

This is the single most common string bug in Java. == asks *"are these the same object?"*; .equals asks *"do these have the same characters?"*. For strings you almost always want .equals.

Building strings in a loop: use StringBuilder

Because every + on strings creates a new object, concatenating inside a loop is quadratic — it copies all the characters built so far on every iteration. StringBuilder holds a mutable char buffer and appends in place, then you call toString() once at the end.

Worked example. Join the numbers 0..4 with dashes.

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
    if (i > 0) sb.append('-');
    sb.append(i);
}
String result = sb.toString();   // "0-1-2-3-4"

The loop appends into one growing buffer instead of allocating a new String each pass. StringBuilder is the unsynchronized (faster, single-thread) sibling of the older StringBuffer.

NORMAL ~/memra/learn/comp-308/immutable-strings-stringbuilder utf-8 LF