Home/Learn/Java A–Z/Strings & StringBuilder

Strings & StringBuilder

Beginner
Java Fundamentals

Understand String immutability, the string pool, all essential String methods, and when to use StringBuilder for performance.

Overview

String is the most-used class in Java and one of the most misunderstood. Strings are immutable — every operation that appears to modify a String actually creates a new object. Java maintains a String pool in the heap where interned literals are stored and reused. For building strings dynamically (in loops, for example), StringBuilder is dramatically faster than using + because it avoids creating throwaway String objects on every concatenation.

Immutability & the String Pool

When you write String s = "hello", Java looks in the string pool first. If "hello" already exists there, s points to that same object. If not, a new object is created in the pool. This is why == works for literal comparisons — they point to the same pooled instance. But String s = new String("hello") always creates a new heap object outside the pool, so == fails.

String.intern() manually adds a string to the pool and returns the pooled reference. In practice, rely on .equals() for all string comparisons — never ==.

StringPool.java
public class StringPool {
    public static void main(String[] args) {
        // Literals go to the string pool
        String a = "hello";
        String b = "hello";
        System.out.println(a == b);       // true  — same pooled object
        System.out.println(a.equals(b));  // true

        // new String() bypasses the pool
        String c = new String("hello");
        System.out.println(a == c);       // false — different heap objects
        System.out.println(a.equals(c));  // true  — same content

        // intern() returns the pooled reference
        String d = c.intern();
        System.out.println(a == d);       // true  — now pointing to pool

        // Strings are immutable — every "change" creates a new object
        String s = "Java";
        s = s + " 21";   // s now points to a NEW String "Java 21"
        System.out.println(s);            // Java 21
        // The original "Java" object is unchanged (and eventually GC'd)
    }
}

Essential String Methods

The String class has 60+ methods. These are the ones you need to know cold for both daily development and interviews:

length(), charAt(i), indexOf(str), lastIndexOf(str) substring(start), substring(start, end) — end is exclusive toUpperCase(), toLowerCase(), trim(), strip() — strip() is Unicode-aware (Java 11+) startsWith(prefix), endsWith(suffix), contains(seq) replace(old, new), replaceAll(regex, new) split(regex), join(delim, parts) isEmpty(), isBlank() — isBlank() also catches whitespace-only (Java 11+) compareTo(), compareToIgnoreCase() formatted(args) / String.format(fmt, args) — printf-style

StringMethods.java
public class StringMethods {
    public static void main(String[] args) {
        String s = "  Hello, Java World!  ";

        // Trimming
        System.out.println(s.trim());           // "Hello, Java World!"
        System.out.println(s.strip());          // same, but Unicode-aware (Java 11)

        String t = "Hello, Java World!";
        System.out.println(t.length());         // 18
        System.out.println(t.charAt(7));        // J
        System.out.println(t.indexOf("Java"));  // 7
        System.out.println(t.substring(7, 11)); // Java
        System.out.println(t.toUpperCase());    // HELLO, JAVA WORLD!
        System.out.println(t.replace("Java", "Python")); // Hello, Python World!

        // Split and join
        String csv = "one,two,three";
        String[] parts = csv.split(",");
        System.out.println(parts.length);               // 3
        System.out.println(String.join(" | ", parts));  // one | two | three

        // Blank / empty
        System.out.println("".isEmpty());    // true
        System.out.println("  ".isBlank());  // true (Java 11+)

        // Formatting
        String msg = "Score: %d / %d (%.1f%%)".formatted(87, 100, 87.0);
        System.out.println(msg);  // Score: 87 / 100 (87.0%)

        // chars() stream (Java 9+)
        long vowels = t.chars()
            .filter(c -> "aeiouAEIOU".indexOf(c) >= 0)
            .count();
        System.out.println("Vowels: " + vowels);  // 5
    }
}

StringBuilder & Performance

Using + inside a loop is O(n²) because each concatenation allocates a new String and copies all previous characters. StringBuilder uses a resizable char[] buffer internally — append() is amortized O(1).

StringBuffer is the thread-safe equivalent of StringBuilder, but its synchronization overhead makes it rarely useful. Prefer StringBuilder in single-threaded code (i.e., almost always).

The compiler automatically converts simple a + b + c into a StringBuilder chain, but NOT when concatenation is inside a loop — that optimisation must be done manually.

StringBuilderDemo.java
public class StringBuilderDemo {
    public static void main(String[] args) {
        // BAD: O(n²) — creates a new String on every iteration
        String bad = "";
        for (int i = 0; i < 5; i++) bad += i;  // avoid in real code
        System.out.println(bad);  // 01234

        // GOOD: O(n) — StringBuilder's buffer grows as needed
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 5; i++) sb.append(i);
        System.out.println(sb.toString());  // 01234

        // StringBuilder API
        StringBuilder demo = new StringBuilder("Hello");
        demo.append(", ").append("World");   // Hello, World
        demo.insert(5, " Java");              // Hello Java, World
        demo.delete(5, 10);                   // Hello, World
        demo.reverse();                       // dlroW ,olleH
        System.out.println(demo);

        // Capacity management (optional optimisation)
        StringBuilder sb2 = new StringBuilder(256); // pre-allocate buffer
        sb2.append("Pre-allocated for performance");
        System.out.println(sb2.capacity());  // at least 256
    }
}

Key Points to Remember

  • Strings are immutable — every modification creates a new String object; the original is unchanged
  • String literals share pooled instances; new String() bypasses the pool — always compare with .equals()
  • Use StringBuilder (not +) in loops to avoid O(n²) concatenation cost
  • strip() (Java 11+) is Unicode-aware; prefer it over trim() for modern code
  • isBlank() (Java 11+) returns true for empty strings AND strings containing only whitespace
  • substring(start, end) — end index is exclusive; substring(7, 11) gives 4 characters

Practice Strings & StringBuilder in the Playground

Run and modify code directly in your browser - no setup needed.

Interview Questions

Sign in to ask Aria
1

Why is String immutable in Java? What are the benefits?

MediumGoogle
2

What is the String pool? How does string interning work?

MediumAmazon
3

What is the difference between StringBuilder and StringBuffer?

EasyTCS
4

Why should you not use == to compare Strings in Java?

EasyInfosys
5

Reverse a String without using StringBuilder.reverse()

EasyMicrosoft

Ask Aria about Strings & StringBuilder

Your personal AI tutor — ask anything about this concept