1.4 Text Blocks, String Immutability, and StringBuilder APIs

Key Takeaways

  • Text blocks (standardized in Java 15 by JEP 378) begin with three double quotes (""") followed by optional whitespace and a mandatory line terminator; no content can appear on the opening delimiter line.

  • The compiler strips incidental indentation based on the leftmost non-whitespace character or the position of the closing """ delimiter; escape sequence \s preserves trailing spaces, while \ suppresses line breaks.

  • String instances are immutable and stored in the String Constant Pool when created via literals or intern(); string transformation methods return new instances and never alter the original string.

  • Java 11 through 17 introduced powerful String methods including strip(), isBlank(), lines(), repeat(), formatted(), indent(), and transform().

  • StringBuilder provides an unsynchronized, mutable character sequence with dynamic capacity; it does not override equals() or hashCode(), meaning equals() tests reference identity rather than character content.

Last updated: October 2026

Text Blocks, String Immutability, and StringBuilder APIs

String processing is central to Java development and exam assessments. Java SE 17 includes text blocks (standardized in Java 15 via JEP 378), modern String inspection and transformation methods added across Java 11–17, and high-performance in-place mutation using StringBuilder.


Text Blocks Syntax and Indentation Algorithms

A text block is a multi-line string literal that begins and ends with three double-quote characters ("""). It eliminates the need for manual escape sequences (\n, \") when authoring embedded HTML, SQL, JSON, or XML snippets.

Delimiter Requirements

The opening """ delimiter may be followed only by optional white space and then a line terminator. You cannot place actual text content on the same line as the opening """:

// COMPILE ERROR: illegal text block open delimiter sequence, missing newline
// String bad = """SELECT * FROM users""";

// Correct syntax:
String query = """
    SELECT id, name
    FROM users
    WHERE status = 'ACTIVE';
    """;

Incidental vs. Essential Whitespace

Java separates indentation into incidental whitespace (boilerplate indentation added by an IDE or developer to keep code aligned) and essential whitespace (indentation intended to remain in the final string). During compilation, the compiler executes a three-step normalization process:

  1. Line terminators are normalized to standard newline characters (\n).
  2. Incidental whitespace is stripped: The compiler calculates the common minimum leading whitespace across all non-blank lines and the line containing the closing """ delimiter.
  3. Escape sequences are interpreted.
String block1 = """
        Red
        Green
        Blue
        """; // Closing delimiter indented 8 spaces; all lines have 8 leading spaces stripped
// Result: "Red\nGreen\nBlue\n"

String block2 = """
        Red
        Green
        Blue
"""; // Closing delimiter at column 0 (0 spaces)
// Result: "        Red\n        Green\n        Blue\n"

Tip

Closing Delimiter Controls Indentation Baseline Placing the closing """ on its own line allows you to set the indentation margin. If you move the closing delimiter to the far left margin (column 0), all leading whitespace on every line becomes essential and is preserved!

Text Block Escape Sequences

Inside text blocks, double quotes (") and double pairs ("") do not require escaping. Escaping is only required for three consecutive quotes (\"\"\"). Java introduces two specific escape sequences for text blocks:

  • \ (Line continuation): Suppresses the line break, joining two lines into a single logical line.
  • \s (Explicit space): Translates to an ASCII space character (\u0020) and preserves trailing whitespace that would otherwise be trimmed by the text block compiler algorithm.
String singleLine = """
    SELECT id, name \
    FROM employees \
    WHERE active = true;
    """;
// Result: "SELECT id, name FROM employees WHERE active = true;\n"

String Immutability and the String Constant Pool

String objects in Java are immutable. Once created, their internal byte arrays cannot be modified. Any method that appears to modify a String (such as concat(), replace(), or toLowerCase()) creates and returns a brand-new String object.

The String Constant Pool and intern()

The JVM maintains a specialized memory region inside the heap called the String Constant Pool to conserve memory:

  • String Literals: Automatically interned into the pool. Identical literals share the same object reference.
  • new String("abc"): Explicitly bypasses the pool, allocating a new, distinct String object on the heap.
  • intern(): Searches the pool for a string with equal character content. If found, returns the pooled reference; if not found, adds the string to the pool and returns its reference.
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
String s4 = s3.intern();

System.out.println(s1 == s2); // true (both reference the same pooled literal)
System.out.println(s1 == s3); // false (s3 is a separate heap instance)
System.out.println(s1 == s4); // true (s4 refers to the pooled instance returned by intern())

Compile-Time Constant Concatenation

Expressions composed purely of compile-time constants (literals or final variables) are evaluated at compile time and pooled. Expressions involving non-final variables are evaluated at runtime, producing new heap instances:

String base = "Java";
final String finalBase = "Java";

String test1 = base + " 17";        // Runtime concatenation -> new heap object
String test2 = finalBase + " 17";   // Compile-time constant expression -> interned literal
String literal = "Java 17";

System.out.println(test1 == literal); // false
System.out.println(test2 == literal); // true

Modern String Methods (Java 11 through Java 17)

Modern Java versions introduced powerful methods on java.lang.String:

MethodIntroducedPurpose / Behavior
strip()Java 11Removes leading and trailing whitespace using Unicode-aware codepoints (replaces legacy trim(), which only strips ASCII ≤\le 32).
stripLeading()Java 11Removes only leading whitespace.
stripTrailing()Java 11Removes only trailing whitespace.
isBlank()Java 11Returns true if string is empty (length() == 0) or contains only white space codepoints.
lines()Java 11Returns a Stream<String> splitting lines on \n, \r, or \r\n.
repeat(int n)Java 11Returns string concatenated with itself n times.
formatted(Object... args)Java 15Instance method equivalent to String.format(this, args).
indent(int n)Java 12Adjusts indentation of every line by n spaces (removes if negative) and normalizes line endings to \n.
transform(Function<String, R> f)Java 12Applies the function to this string and returns the result R (enables fluent chaining).
String text = "  \u2000Hello Java\u2000  ";
System.out.println(text.trim().length());  // trim() fails to remove Unicode whitespace \u2000
System.out.println(text.strip().length()); // strip() removes full Unicode whitespace

"abc ".repeat(3); // "abc abc abc "
"line1\nline2".lines().count(); // 2

String result = "hello"
    .transform(String::toUpperCase)
    .transform(s -> s + " WORLD"); // "HELLO WORLD"

StringBuilder vs. StringBuffer

StringBuilder (introduced in Java 5) and StringBuffer (legacy Java 1.0) represent mutable sequences of characters:

  • StringBuilder: Not thread-safe (methods are unsynchronized). Offers maximum performance for single-threaded usage.
  • StringBuffer: Thread-safe (methods are synchronized). Carries locking overhead; rarely needed in modern code.

Internal Capacity Mechanics

A StringBuilder maintains an internal buffer with an initial capacity:

  • new StringBuilder(): Default capacity of 16 characters.
  • new StringBuilder(int capacity): Explicit capacity set to specified integer.
  • new StringBuilder(String str): Capacity initialized to str.length() + 16.

When appends exceed capacity, the buffer automatically expands to (oldCapacity * 2) + 2.

Mutation Methods and Method Chaining

All mutating methods return a reference to this (StringBuilder), enabling fluent method chaining:

StringBuilder sb = new StringBuilder("Java");
sb.append(" 17")             // "Java 17"
  .insert(0, "Modern ")      // "Modern Java 17"
  .replace(0, 6, "Fast")     // "Fast Java 17"
  .delete(4, 9)              // "Fast 17" (deletes indices 4 through 8 inclusive)
  .reverse();                // "71 tsaF"

Warning

The StringBuilder.equals() Trap Neither StringBuilder nor StringBuffer overrides equals() or hashCode() from java.lang.Object! Calling sb1.equals(sb2) performs reference equality (==), returning false even if both builders hold identical characters. To compare text content, convert them to strings with .toString().equals(...) or use sb1.compareTo(sb2) == 0.


Core String Methods You Must Trace by Hand

Most String questions on the exam are about exact return values and index boundaries rather than modern additions. Indexes are zero-based, and every end index is exclusive.

Call on String s = "animals";ResultRule
s.length()7Number of char values
s.charAt(6)'s'charAt(7) throws StringIndexOutOfBoundsException
s.substring(3)"mals"From index 3 to the end
s.substring(3, 4)"m"end is exclusive
s.substring(3, 3)""Equal indexes return an empty string
s.substring(4, 3)throws StringIndexOutOfBoundsExceptionbegin greater than end
s.indexOf('a') / s.indexOf("al")0 / 4First match, or -1 if absent
s.indexOf('a', 4) / s.lastIndexOf('a')4 / 4The second argument is the start index
"abc".compareTo("abd")-1Lexicographic, by char code; "apple".compareTo("app") is 2 (length difference)
"abc".equalsIgnoreCase("ABC")trueequals is case-sensitive
"banana".replace('a', 'o')"bonono"Replaces all matches; there is also a CharSequence overload
"a,b,,c,,".split(",")[a, b, , c] (length 4)Trailing empty strings are removed
String.join("-", "a", "b", "c")"a-b-c"Static method
"x" + null"xnull"Concatenation converts null to the text null

Other methods to recognize: startsWith, endsWith, contains, toUpperCase, toLowerCase, trim, isEmpty (length 0), isBlank (only whitespace), concat, and chars() (an IntStream). Because strings are immutable, a statement such as t.concat(" 17"); that ignores the return value leaves t unchanged.

More StringBuilder methods

StringBuilder also offers deleteCharAt(int), setCharAt(int, char) (returns void, so it cannot be chained further), setLength(int), indexOf(String), charAt(int), and length(). For example, new StringBuilder("abcdef").deleteCharAt(1).insert(2, "-") produces "ac-def", and setLength(2) on "hello" truncates it to "he".

Test Your Knowledge

Which of the following text block declarations results in a compile-time error?

A

A text block using the line continuation escape sequence \ to combine lines:

String greeting = """
    Hello \
    World!
    """;
B

A text block where the opening delimiter is followed by a newline and the closing delimiter is on its own line:

String query = """
    SELECT * 
    FROM users;
    """;
C

A text block where text content appears on the same line as the opening delimiter:

String query = """SELECT *
    FROM users;
    """;
D

A text block containing unescaped double quotes inside the string body:

String json = """
    {"name": "Alice"}
    """;
Test Your Knowledge

What is the output of the following code snippet?

String str = "  Java 17  ";
String res = str.strip().transform(s -> s.repeat(2));
System.out.println(res);
A

Java 17

B

Java 17Java 17

C

Java 17 Java 17

D

Java 17 Java 17

Test Your Knowledge

Consider the following code snippet:

StringBuilder sb1 = new StringBuilder("Java");
StringBuilder sb2 = new StringBuilder("Java");
StringBuilder sb3 = sb1.append("17");
System.out.print((sb1 == sb3) + " ");
System.out.print(sb1.equals(sb2) + " ");
System.out.print(sb1.toString().equals("Java17"));

What does this code print?

A

false true true

B

true false true

C

false false true

D

true true true

Test Your Knowledge

What is the output of the following code?

String s = "animals";
String t = s.substring(2, 5);
s.toUpperCase();
System.out.println(t + " " + s.indexOf('a', 1) + " " + s);
A

ima 4 animals

B

imal 4 animals

C

ima 0 animals

D

ima 4 ANIMALS

Sections you finish are checked off in the contents.