Java Strings: Immutability, the String Pool and StringBuilder
Codevity Admin · 10/25/2026
Step 4 of 38 · Java Interview Preparation for Beginners · Stage 1: Roadmap and language fundamentals
Codevity Admin · 10/25/2026
Strings are the most common interview topic after OOP. Four ideas cover almost every question: immutability, the string pool, == versus equals(), and StringBuilder.
A String object never changes after it is created. Methods such as toUpperCase(), replace() and trim() return a new string.
public class Builder {
public static void main(String[] args) {
String s = "hello";
s.toUpperCase(); // returns a new String; the result is thrown away
System.out.println(s); // hello
s = s.toUpperCase();
System.out.println(s); // HELLO
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append(i).append(',');
}
sb.setLength(sb.length() - 1); // remove the trailing comma
System.out.println(sb); // 1,2,3,4,5
System.out.println(new StringBuilder("stressed").reverse()); // desserts
}
}Why immutable?
HashMap keys.String literals are stored in a special area of the heap called the string pool. Two identical literals refer to the same pooled object. new String("hello") always creates a new object, even though "hello" is already in the pool.
public class StringPool {
public static void main(String[] args) {
String a = "hello";
String b = "hello";
String c = new String("hello");
System.out.println(a == b); // true (both literals point to the same pooled object)
System.out.println(a == c); // false (new String always creates a new object)
System.out.println(a.equals(c)); // true
System.out.println(a == c.intern()); // true (intern() returns the pooled instance)
String part = "hel";
String joined = part + "lo"; // computed at run time: a new object
System.out.println(a == joined); // false
final String constant = "hel";
System.out.println(a == constant + "lo"); // true (a constant expression, folded at compile time)
}
}== compares references (are these the same object?). .equals() compares content. Always use .equals() for text.intern() returns the pooled instance of a string.new String("hello") creates up to two objects: the pooled literal (if not already there) and the new heap object. It is almost never the right thing to write.
String | StringBuilder | StringBuffer | |
|---|---|---|---|
| Mutable | No | Yes | Yes |
| Thread-safe | Yes (immutable) | No | Yes (methods are synchronized) |
| Speed | Creates new objects on change | Fastest | Slower, because of locking |
| Use for | Fixed text | Building text in one thread (the default choice) | Legacy code that shares a buffer between threads |
Every += on a string inside a loop creates a new string and copies the old characters, so the work grows quadratically. Use a StringBuilder inside loops. A single expression like is fine: the compiler optimizes it.
, and came in Java 11, and text blocks () in Java 15. Also remember , , , , and .
a + b + cstrip()isBlank()repeat()"""charAtsubstringindexOfsplitcompareTotoCharArray==s.trim()s.replace(...)+StringBuilder.equals()nullObjects.equals(a, b)truefalseStringPoolMappublic class Comparing {
public static void main(String[] args) {
String name = "Asha";
System.out.println("asha".equalsIgnoreCase(name)); // true
System.out.println("Asha".equals(name)); // true
String maybeNull = null;
System.out.println("Asha".equals(maybeNull)); // false (the literal on the left avoids a NullPointerException)
System.out.println(" padded ".strip() + "|"); // padded|
System.out.println("ab".repeat(3)); // ababab
System.out.println(" ".isBlank()); // true
System.out.println(String.join(" | ", "a", "b", "c")); // a | b | c
String json = """
{"name": "Asha"}
""";
System.out.print(json); // {"name": "Asha"}
}
}