StringBuilder and StringBuffer

Strings never change, so building a big report with += creates thousands of throwaway objects. StringBuilder is a String you can edit: one object, one growing buffer. You'll see how append and insert work inside, why capacity doubles, how StringBuffer differs, the equals() trap, and then practise with 11 problems.

Module 4 · Arrays and Strings⏱ 22 minBeginner11 practice problems
1 The story

The report that took forever

Riya writes a program to print the fest's registration report: one line for each of 50,000 students, built with report += line;. For 50 students it was instant. For 50,000 it runs, and runs, and the laptop fan starts screaming.

String += : a new object every time garbagegarbagegarbagegarbagecurrent each step copies everything so far StringBuilder: one object, edited in place Row 1 Row 2 Row 3 … spare room sb.append(line); adds to the end; grows only when full myphatshala.in
Riya

Sir, it's just adding one line at a time. Why is it so slow?

Arjun Sir

Because Strings never change. Every += builds a brand-new String and copies the whole report so far into it. Line 50,000 copies 49,999 lines. That's crores of characters copied.

Riya

So I need a String that can change?

Arjun Sir

Exactly: StringBuilder. It keeps one buffer with spare room and just writes the new line at the end. Same code shape, and your report prints in a blink.

2 Definition

What are StringBuilder and StringBuffer?

Formal definition (write this in exams)

StringBuilder and StringBuffer are classes in java.lang that represent a mutable sequence of characters. They store characters in an internal buffer with a capacity that grows automatically. Methods like append, insert, delete and reverse modify the same object. StringBuffer (Java 1.0) is synchronized and thread-safe; StringBuilder (Java 5) is not synchronized and is faster for single-threaded use.

In simple words

A String is a printed card. A StringBuilder is a whiteboard: write more, erase a bit, insert a word, and when you're done, take a photo with toString().

Words you'll meet in this lesson

MutableCan be changed after creation.
BufferThe internal array that holds the characters.
length()How many characters are in use right now.
capacity()How many fit before the buffer must grow. Default 16.
Method chainingappend returns the same builder, so calls can be joined.
SynchronizedOnly one thread at a time may use the object (StringBuffer).

String vs StringBuilder vs StringBuffer

StringStringBuilderStringBuffer
Mutable?NoYesYes
Thread-safe?Yes (immutable)NoYes (synchronized)
Speed for building textSlow in loopsFastestSlightly slower (locking)
equals() compares text?YesNo (same object only)No (same object only)
SinceJava 1.0Java 5Java 1.0
Use forValues, keys, constantsBuilding text in a methodLegacy code; rarely needed today

Exam tip: new StringBuilder() has capacity 16; new StringBuilder("abc") has capacity 16 + 3 = 19. When full, the new capacity is old × 2 + 2 (16 → 34), or more if needed.

3 Types and ways to use it

The editing methods

public class Main {
    public static void main(String[] args) {
        StringBuilder s = new StringBuilder("Hello World");
        s.insert(5, ",");          System.out.println(s);
        s.delete(5, 6);            System.out.println(s);
        s.replace(6, 11, "Java");  System.out.println(s);
        s.setCharAt(0, 'J');       System.out.println(s);
        s.deleteCharAt(0);         System.out.println(s);
        s.reverse();               System.out.println(s);
    }
}
Hello, World Hello World Hello Java Jello Java ello Java avaJ olle
MethodWhat it does
append(x)Adds x (any type) at the end; returns the same builder
insert(i, x)Puts x before index i, shifting the rest right
delete(start, end)Removes indexes start to end − 1 (end excluded, like substring)
deleteCharAt(i)Removes one character
replace(start, end, str)Replaces a range with str (note: a range, unlike String.replace)
setCharAt(i, ch)Overwrites one character: impossible with String
reverse()Reverses in place
length(), charAt, indexOf, substringRead-only methods, like String's
toString()Copies the current contents into a new, immutable String

The equals() trap: StringBuilder doesn't override equals, so new StringBuilder("hi").equals(new StringBuilder("hi")) is false. Compare a.toString().equals(b.toString()), or a.compareTo(b) == 0 (Java 11+). Don't use builders as HashMap keys.

4 Step by step

Building text the fast way

  1. Create one builder

    StringBuilder sb = new StringBuilder();
    One object with an empty buffer of 16 characters. If you know the result will be big, pass a size: new StringBuilder(10_000).
  2. Append in the loop

    for (int i = 1; i <= 5; i++) {
        sb.append("Row ").append(i).append('\n');
    }
    Each append writes characters into the spare room at the end. No new objects, and earlier text is never copied, except when the buffer has to grow.
  3. Edit anywhere

    sb.insert(0, "REPORT\n");
    Insert shifts the existing characters right inside the buffer. Handy, but inserting at the front of a huge builder many times is slow: append when you can.
  4. Grow when full

    If the text no longer fits, the builder makes a bigger array (about double) and copies once.

    Doubling means growth happens rarely: building n characters costs about n copies in total, instead of about n² with +=.
  5. Finish with toString()

    String report = sb.toString();
    Creates an immutable String snapshot. Later changes to sb don't affect report. Pass Strings around, keep builders local.
5 See it happen

One buffer, edited in place: both views

Left: the code and the builder's contents. Right: the builder's internal buffer, its length and its capacity.

Inside a StringBuilder 6 steps
What you see StringBuilder sb = new StringBuilder(); sb.append("Java"); sb.append(' ').append(21); sb.insert(0, "Hi "); sb.append(" is fun"); String s = sb.toString(); sb → "" sb → Java sb → Java 21 same object? true sb → Hi Java 21 sb → Hi Java 21 is fun length 17 (was capacity 16) s → Hi Java 21 is fun s is a String: immutable An empty builder. Text added at the end. Chained appends, still one object. Inserted at the front. It no longer fits in 16: it grows. A String snapshot of the result. myphatshala.in
Behind the screen sb → one StringBuilder object (#1) length 0 capacity 16 length 4 capacity 16 length 7 capacity 16 length 10 capacity 16 length 17 capacity 34 015 JHaivaJa2v1a21isfu ↑ "Hi " written at 0–2; "Java 21" shifted right by 3 old buffer full → copied once into a bigger one Hi Java 21 is fun 17 used / 34 (16×2+2) s → new String (a copy) "Hi Java 21 is fun" 16 empty slots ready, nothing used yet. Characters written into slots 0–3. More slots filled; no new objects. Old chars moved right by 3 to make room. New array of 34, copied once, then appended. The String is separate: editing sb won't change s. myphatshala.in
6 Real-world use

StringBuilder in real systems

Any time text is assembled piece by piece, especially in loops, a builder is used directly or behind the scenes.

Watch it with an example: building a receipt line by line

A shop app adds 3 items to a receipt. Compare String += (a new object every time) with one StringBuilder that grows in place.

String += vs StringBuilder 6 steps
Animated example String r = ""; r += item; StringBuilder sb = new StringBuilder(); sb.append(item); #1 "Tea 10;" #1 garbage #2 "Tea 10;Vada 15;" #2 garbage #3 "Tea 10;Vada 15;Chai 10;" #3 garbage r → #1 r → #2 r → #3 3 appends = 3 new String objects (and copies) Tea 10; Tea 10;Vada 15; Tea 10;Vada 15;Chai 10; 23 chars > 16: buffer replaced once by a 34-slot one 15 of 16 slots used: still fits sb → #1 (the same object every time) sb.toString() → one final String In a loop of 10,000 items this is the difference between thousands of copies and one growing buffer. myphatshala.in
id,name,total1,Riya,1702,Kabir,148…

1. Reports and exports

CSV downloads, statements and audit reports are built line by line. With a builder, a 1 lakh-row export takes milliseconds instead of minutes.

Rows→sb.append(row)→CSV file
SELECT * FROM ordersWHERE city = ?AND total > ?

2. Dynamic queries and URLs

Search filters add conditions only when the user picks them: WHERE, then AND city = ?, then AND price < ?. Values still go in as parameters, never pasted into the text.

Chosen filters→append(" AND …")→Safe query

3. Messages, HTML and JSON

Email bodies, simple HTML pages and JSON payloads are often assembled with a builder or by libraries that use one internally.

Data→append tags / fields→Email / JSON
"a" + b + "c"javac optimises

4. What javac does for you

A single expression like "Hi " + name + "!" is already compiled efficiently (Java 9+ uses a special concatenation call). The problem is only += repeated across loop iterations.

One-line +→fine as is→Loops: use a builder

Examples are simplified. Very large outputs are usually written straight to a file or network stream rather than built fully in memory.

7 Run the code

Riya's report, fixed

public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 5; i++) {
            sb.append("Row ").append(i).append('\n');
        }
        sb.insert(0, "REPORT\n");
        sb.append("END");
        System.out.println(sb);
        System.out.println("Characters: " + sb.length());
        String report = sb.toString();
        System.out.println(report.startsWith("REPORT"));
    }
}
REPORT Row 1 Row 2 Row 3 Row 4 Row 5 END Characters: 40 true
  • sb.append("Row ").append(i).append('\n')Chaining works because each append returns the same builder.
  • sb.insert(0, "REPORT\n")Adds the heading in front after the rows are built.
  • System.out.println(sb)println calls toString() for you.
  • String report = sb.toString()Turn it into a String before returning, comparing or storing it.
8 Line by line

Building "1-2-3" in one object

Watch the heap: the StringBuilder (#1) changes in place. Only toString() creates a String.

Worked examples: real problems, solved and traced in memory

Three real jobs where text is built or edited step by step. Run each solution, then step through it and watch a single StringBuilder object change in place, including its length and capacity.

Example 1Operations · daily report

Build a report and watch the buffer grow

Problem statement

An operations report lists the rows processed today, one per line. Build the text with a StringBuilder and print it, along with the final length and capacity.

Input
rows = 3
Expected output
Row 1
Row 2
Row 3
18 chars, capacity 34

Approach

  1. Create one StringBuilder (capacity 16 by default).
  2. Append each line in the loop; no new String objects are created per step.
  3. When the text no longer fits, the builder grows its buffer once (16 × 2 + 2 = 34).

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Payments · receipt

Mask a card number in place

Problem statement

A receipt must show only the last 4 digits of a card number. Write mask(card) that replaces every earlier digit with X using a StringBuilder, and returns the masked String.

Input
card = "41112222" (shortened to 8 digits to keep the trace short)
Expected output
XXXX2222

Approach

  1. Copy the card number into a StringBuilder: Strings can't be edited, builders can.
  2. Loop over all positions before the last 4 and call setCharAt(i, 'X').
  3. Return toString(), an immutable snapshot for the receipt.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3Food delivery · cart

A method that adds to the caller's cart summary

Problem statement

A cart summary is built by a helper addItem(summary, item, price) that appends one line each time it's called. Unlike a String, the caller's builder must show every added item afterwards.

Input
items: ("Dosa", 90), ("Coffee", 40)
Expected output
CART
Dosa Rs 90
Coffee Rs 40

Approach

  1. Create the summary builder once in main.
  2. Pass it to addItem: the method receives a copy of the reference, so both point to the same object.
  3. append changes that shared object, so main sees the result without any return value.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 4.6 in one screen

  • StringBuilder / StringBuffer = mutable text; methods change the same object.
  • append, insert, delete(start, end), deleteCharAt, replace(start, end, s), setCharAt, reverse.
  • Methods return the same builder → chaining.
  • Capacity 16 by default (16 + text length with a String); grows to old × 2 + 2.
  • Use a builder for text built in loops; one-line + is fine.
  • equals on builders compares identity: use toString().equals.
  • StringBuffer = synchronized; prefer StringBuilder as a local variable.

Interview and viva questions

String vs StringBuilder vs StringBuffer?

String is immutable and thread-safe because it can't change. StringBuilder is mutable and fastest, but not thread-safe. StringBuffer is mutable and synchronized (thread-safe), with some locking overhead. Use String for values, StringBuilder for building text, and StringBuffer only when legacy APIs need it.

Is "a" + b + "c" slow? Should every + become a StringBuilder?

No. A single concatenation expression is compiled efficiently (with StringBuilder in old Java, with invokedynamic-based concatenation since Java 9). Only repeated += across loop iterations causes the n² copying problem.

How does StringBuilder grow?

It keeps a character array with spare capacity. When an append doesn't fit, it allocates a new array of about twice the size (old × 2 + 2, or the required size if larger) and copies the old characters once.

Why doesn't StringBuilder override equals and hashCode?

Because it's mutable: its content can change at any time, so content-based equality and hash codes would be unreliable (for example, as HashMap keys). Convert to String to compare.

Is StringBuffer enough to make code thread-safe?

Each single method call is synchronized, but a sequence of calls (check length, then append) isn't atomic. In practice, give each thread its own StringBuilder as a local variable; that's both safe and fast.

Practice problems

Whenever you build or edit text step by step, reach for StringBuilder. Try each problem with String first in your head, then notice how much simpler the builder makes it. The last three are real business tasks.

P1Easy

Reverse a sentence's characters

Reverse a string using StringBuilder.

Input
s = "MyPhatshala"
Expected output
alahstahPyM
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String s = "MyPhatshala";
        String rev = new StringBuilder(s).reverse().toString();
        System.out.println(rev);
    }
}
alahstahPyM

How it works: wrap the String in a builder, call reverse() (which changes the builder in place and returns it), then toString() to get a String back. One object does the work, instead of one new String per character.

P2Easy

Comma-separated list without a trailing comma

Print the numbers 1 to 10 as 1, 2, 3, …, 10, with no comma after the last one.

Input
n = 10
Expected output
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        int n = 10;
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= n; i++) {
            if (sb.length() > 0) sb.append(", ");
            sb.append(i);
        }
        System.out.println(sb);
    }
}
1, 2, 3, 4, 5, 6, 7, 8, 9, 10

How it works: add the separator before every item except the first (when the builder is still empty). append accepts ints, chars, booleans and more. println(sb) calls toString() automatically.

P3Easy

Sentence palindrome

Check if a sentence is a palindrome when you ignore spaces, punctuation and case.

Input
s = "Was it a car or a cat I saw?"
Expected output
wasitacaroracatisaw -> palindrome
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String s = "Was it a car or a cat I saw?";
        StringBuilder clean = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (Character.isLetterOrDigit(ch)) clean.append(Character.toLowerCase(ch));
        }
        String forward = clean.toString();
        String backward = clean.reverse().toString();
        System.out.println(forward + " -> " + (forward.equals(backward) ? "palindrome" : "not a palindrome"));
    }
}
wasitacaroracatisaw -> palindrome

How it works: keep only letters and digits, lower-cased. Take the String before reversing, because reverse() changes the builder itself. Compare with equals; builders themselves don't compare content with equals.

P4Medium

Remove all vowels

Delete every vowel from a word, editing a builder in place.

Input
word = "Education"
Expected output
dctn
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Education");
        for (int i = sb.length() - 1; i >= 0; i--) {
            if ("aeiouAEIOU".indexOf(sb.charAt(i)) != -1) {
                sb.deleteCharAt(i);
            }
        }
        System.out.println(sb);
    }
}
dctn

How it works: deleting shifts the later characters left. Going backwards means the shift only affects indexes we've already checked. A forward loop would skip the character right after each deletion. "aeiouAEIOU".indexOf(ch) is a quick “is it a vowel?” test.

P5Medium

Run-length compression

Compress repeated letters: aaabbcdddd becomes a3b2c1d4.

Input
s = "aaabbcdddd"
Expected output
a3b2c1d4
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String s = "aaabbcdddd";
        StringBuilder out = new StringBuilder();
        int count = 1;
        for (int i = 1; i <= s.length(); i++) {
            if (i < s.length() && s.charAt(i) == s.charAt(i - 1)) {
                count++;
            } else {
                out.append(s.charAt(i - 1)).append(count);
                count = 1;
            }
        }
        System.out.println(out);
    }
}
a3b2c1d4

How it works: count while the character repeats; when it changes (or the string ends, i == length), append the letter and its count. Running i one past the end is what flushes the last group. Chained append calls keep it compact.

P6Medium

Remove duplicate characters

Keep only the first occurrence of each character.

Input
s = "programming"
Expected output
progamin
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String s = "programming";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (sb.indexOf(String.valueOf(ch)) == -1) {
                sb.append(ch);
            }
        }
        System.out.println(sb);
    }
}
progamin

How it works: before adding a character, check whether the builder already contains it. StringBuilder's indexOf takes a String, so the char is converted with String.valueOf.

P7Medium

Capitalise with setCharAt

Make the first letter of each word upper case by editing the builder directly.

Input
s = "learn java visually"
Expected output
Learn Java Visually
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("learn java visually");
        for (int i = 0; i < sb.length(); i++) {
            if (i == 0 || sb.charAt(i - 1) == ' ') {
                sb.setCharAt(i, Character.toUpperCase(sb.charAt(i)));
            }
        }
        System.out.println(sb);
    }
}
Learn Java Visually

How it works: unlike String, a builder can change one character in place with setCharAt. A letter starts a word if it's at index 0 or follows a space. No new objects are created inside the loop.

P8Medium

Insert a separator every 4 characters

Format a 16-digit card-style number as groups of 4: 1234 5678 9012 3456.

Input
num = "1234567890123456"
Expected output
1234 5678 9012 3456
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("1234567890123456");
        for (int i = sb.length() - 4; i > 0; i -= 4) {
            sb.insert(i, ' ');
        }
        System.out.println(sb);
    }
}
1234 5678 9012 3456

How it works: inserting from the right means earlier positions aren't shifted by the spaces we've already added. Positions 12, 8 and 4 get a space.

P9Business problem

Indian-style amount formatting

Format amounts with Indian digit grouping: the last 3 digits, then groups of 2. 1234567 → 12,34,567.

Input
amounts = 999, 15000, 1234567, 250000000
Expected output
Rs 999
Rs 15,000
Rs 12,34,567
Rs 25,00,00,000
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        long[] amounts = {999, 15000, 1234567, 250000000};
        for (long amt : amounts) {
            StringBuilder sb = new StringBuilder(String.valueOf(amt));
            int pos = sb.length() - 3;
            while (pos > 0) {
                sb.insert(pos, ',');
                pos -= 2;
            }
            System.out.println("Rs " + sb);
        }
    }
}
Rs 999 Rs 15,000 Rs 12,34,567 Rs 25,00,00,000

How it works: the first comma goes 3 digits from the right, then every 2 digits (lakh, crore). Working right to left with insert keeps positions valid. Invoices and bank apps in India show amounts this way; Java's NumberFormat with an Indian locale can also do it.

P10Business problem

Build a CSV report

Turn arrays of names and marks into CSV text (a header line plus one line per student) ready to save as a file.

Input
names = {"Riya", "Kabir", "Meera"}, marks = {{78, 92}, {81, 67}, {95, 88}}
Expected output
name,maths,science,total
Riya,78,92,170
Kabir,81,67,148
Meera,95,88,183
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        String[] names = {"Riya", "Kabir", "Meera"};
        int[][] marks = {{78, 92}, {81, 67}, {95, 88}};
        StringBuilder csv = new StringBuilder("name,maths,science,total\n");
        for (int i = 0; i < names.length; i++) {
            int total = marks[i][0] + marks[i][1];
            csv.append(names[i]).append(',')
               .append(marks[i][0]).append(',')
               .append(marks[i][1]).append(',')
               .append(total).append('\n');
        }
        System.out.print(csv);
    }
}
name,maths,science,total Riya,78,92,170 Kabir,81,67,148 Meera,95,88,183

How it works: one builder collects the whole file. Chained append calls add each field and separator without creating intermediate Strings. For thousands of rows, this is dramatically faster than +=.

P11Business problem

Mask a card number

On a receipt, show only the last 4 digits of a card number, keeping the spaces: XXXX XXXX XXXX 3456.

Input
card = "1234 5678 9012 3456"
Expected output
XXXX XXXX XXXX 3456
Show solution and explanation
public class Main {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("1234 5678 9012 3456");
        int digitsSeen = 0;
        for (int i = sb.length() - 1; i >= 0; i--) {
            if (Character.isDigit(sb.charAt(i))) {
                digitsSeen++;
                if (digitsSeen > 4) sb.setCharAt(i, 'X');
            }
        }
        System.out.println(sb);
    }
}
XXXX XXXX XXXX 3456

How it works: walk from the right, counting digits; after the 4th digit, overwrite each digit with X using setCharAt. Spaces are left alone. Card rules (PCI DSS) require full numbers never to be displayed or printed.

Real-world scenario questions (asked in company interviews)

Builders fix performance problems, but shared or misused builders cause new bugs. Decide your answer first, then open the model answer.

Code review · performance1–3 years

“Replace every + with StringBuilder”

A reviewer asks you to change String msg = "Order " + id + " placed by " + name; to use StringBuilder “for performance”, while a loop elsewhere uses html += row; for 10,000 rows. What do you say?

The interviewer is checking: do you know where the cost really is, instead of following rules blindly?

Show a strong answer
  • The one-line message is already compiled efficiently; rewriting it only hurts readability.
  • The loop is the real problem: each += copies the growing HTML, about n² work. Change that to a StringBuilder (with an estimated initial capacity).
  • Back the change with a quick measurement so the review is about evidence.

Avoid: applying StringBuilder everywhere “just in case”.

Web backend · concurrency1–3 years

Mixed-up responses under load

To “save memory”, a developer made a static StringBuilder sb shared by a request handler, calling sb.setLength(0) at the start of each request. Under load, users occasionally receive parts of other users' responses, and sometimes an exception. Explain.

The interviewer is checking: do you understand that StringBuilder is not thread-safe and shared state is dangerous?

Show a strong answer
  • A web server handles requests on many threads at once. All of them clear and append to the same buffer, so text from different users mixes, and concurrent resizing can even throw exceptions.
  • Fix: make the builder a local variable inside the method. Each request gets its own, which is cheap and needs no locking.
  • Switching to StringBuffer would stop crashes but still mix content, because a whole response is many calls, not one.
  • This is also a data-leak risk: one user's personal data could appear in another's response.

Avoid: “Use StringBuffer and it's fixed.” The design (shared state) is the bug.

E-commerce · deduplicationFresher

The duplicate check that never finds duplicates

Code builds a product key for each cart item with a StringBuilder (brand + size + colour) and adds it to a HashSet<StringBuilder> to detect duplicate items. Duplicates are never detected. Why?

The interviewer is checking: do you know StringBuilder doesn't implement content equality?

Show a strong answer
  • HashSet uses equals and hashCode. StringBuilder inherits them from Object, so two builders with the same text are different keys.
  • Convert to a String: set.add(sb.toString()) with a HashSet<String>.
  • Even if it worked, a mutable key that changes after insertion would get lost in the set. Keys should be immutable.

Avoid: keeping builders around after construction. Build, then toString().

Banking · statements3+ years

Out of memory on the year-end statement

A service builds a corporate customer's full-year statement (about 200 MB of text) in a StringBuilder, then writes it to a file. It fails with OutOfMemoryError for the biggest customers. The team asks whether a larger initial capacity would help. What do you recommend?

The interviewer is checking: do you know builder growth costs and when to stream instead?

Show a strong answer
  • Each growth step briefly needs both the old and the new array, and Java chars can take 2 bytes each, so peak memory can be several times the final text size.
  • A good initial capacity avoids repeated copies and reduces the peak, which helps for moderately large outputs.
  • For hundreds of MB, don't hold it all in memory: write each line straight to a BufferedWriter or the HTTP response stream as you produce it. Memory then stays small and constant.
  • Consider generating big statements asynchronously and compressing them.

Avoid: just increasing the JVM heap. The next, bigger customer will fail again.