Java StringBuilder

In the last lesson you learned about Java string comparison. A String can never change, so building text in a loop with + creates a new String every time and gets slow. Java’s answer is the StringBuilder, a String-like tool you can change in place.

🤔 Why not just use String?

Building a long line in a loop with + is wasteful. Here is the problem.

This loop joins the numbers 1 to 1000 into one String using +.

String result = "";
for (int i = 1; i <= 1000; i++) {
result = result + i + " "; // ❌ makes a brand new String every single time
}

A String is immutable, so result + i cannot edit the old String. Every pass Java must:

  • Create a new String object.
  • Copy all the old characters into it.
  • Add the new piece on the end, then throw the old String away.

The work grows as the text grows. By pass 500 it recopies a long line just to add a couple of characters. So 1000 passes means hundreds of throwaway objects and slow, wasteful copying.

A StringBuilder fixes this. It keeps one changeable buffer of characters, so adding text just extends that same buffer. No recopying, no pile of throwaway objects.

Why String can't just change

String is immutable on purpose. Strings get shared and reused all over a program, so making them unchangeable keeps that sharing safe. StringBuilder is the opposite: it is meant to be your private scratch space while you build, not something to share around.

🧱 Creating a StringBuilder

You make a StringBuilder with new. Start it empty or hand it some text.

StringBuilder sb = new StringBuilder(); // starts empty
StringBuilder greeting = new StringBuilder("Hello"); // starts with text inside
  • sb is an empty, changeable text buffer; greeting already holds “Hello”.
  • You can keep adding to both without Java making a new object each time.
  • Think of a StringBuilder like a whiteboard: write, rub out, add more on the same board. A String is ink on paper, set once and done.

➕ Building text with append

append() is the method you will use most. It adds text to the end of the same builder, in place, and you can chain many appends in one line.

This builds “Hello World” by appending three pieces to one builder.

StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
System.out.println(sb.toString()); // turn it into a real String to print

Here is how it works:

  • Each append adds to the same builder, so no new objects are made.
  • toString() at the end turns the builder into a normal String for printing.
  • append takes more than text: Strings, numbers (append(42)), a char, a boolean, even another object. Java turns each into text for you.

Output

Hello World

You can chain appends like sb.append(a).append(b) because each append returns the same builder, ready for the next call.

🔁 The loop, done right

Here is that loop again, the proper way, with a StringBuilder. We print just 5 numbers, but picture it running 1000 times.

This builds a line of numbers using one builder and chained appends.

public class BuildLine {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append(i).append(" "); // ✅ chained appends, same buffer every time
}
String result = sb.toString();
System.out.println(result);
}
}

The difference from the + version:

  • Each number and space appends to the same builder, so no old text is copied each pass. The text grows in place.
  • sb.append(i).append(" ") chains two appends, since each returns the builder.
  • toString() hands us the finished String once, not a thousand times.

Output

1 2 3 4 5

For 5 numbers you would not notice. The win shows up with large counts: thousands of + passes are much slower. The rule is easy: building text in a loop means StringBuilder.

🛠️ Other useful methods

A StringBuilder can edit text in other ways too. All of these change the builder directly, with no new object made.

This shows insert, append, and reverse on one builder, then replace on another.

StringBuilder sb = new StringBuilder("Hello");
sb.insert(0, ">> "); // add text at a position, push the rest right
sb.append(" World"); // add to the end
sb.reverse(); // flip the whole thing
System.out.println(sb.toString());
StringBuilder name = new StringBuilder("Java");
name.replace(0, 1, "L"); // replace index 0 up to (not including) 1 with "L"
System.out.println(name.toString());

Method by method:

  • insert(0, ">> ") puts text at index 0, sliding the rest right.
  • append(" World") adds to the end.
  • reverse() flips every character, so the line runs backwards.
  • replace(0, 1, "L") swaps index 0 up to (not including) 1 with “L”, turning “Java” into “Lava”.

Output

dlroW olleH >>
Lava

There are removal methods too. This deletes a range of characters, then a single one.

StringBuilder code = new StringBuilder("ABCDEF");
code.delete(1, 3); // remove index 1 up to (not including) 3 -> removes "BC"
System.out.println(code.toString()); // ADEF
code.deleteCharAt(0); // remove the single character at index 0
System.out.println(code.toString()); // DEF
  • delete(start, end) removes a whole range.
  • deleteCharAt(index) removes just one character.
  • Like replace, delete uses the “up to but not including the end” rule.

Output

ADEF
DEF

Two read methods come up a lot: length() counts the characters inside, and setLength() trims or pads the builder.

StringBuilder text = new StringBuilder("Hello World");
System.out.println(text.length()); // 11 characters right now
text.setLength(5); // cut it down to the first 5 characters
System.out.println(text.toString()); // Hello
  • setLength(5) keeps the first 5 characters and drops the rest.
  • setLength(0) empties the builder so you can reuse it.

Output

11
Hello

Here are the methods you will reach for most.

Method What it does
append(x) Adds x to the end
insert(i, x) Inserts x at index i
delete(start, end) Removes characters from start up to end
deleteCharAt(i) Removes the one character at index i
replace(start, end, x) Replaces that range with x
reverse() Flips all the characters
length() How many characters are inside
setLength(n) Trims or pads to n characters
toString() Gives back a normal String

📦 A quick word on capacity

You may hear the word capacity with StringBuilder. It is simple:

  • The builder reserves extra room so it does not grow on every append.
  • length() is how many characters you have; capacity() is the room set aside right now.
  • Append past the capacity and Java enlarges the buffer and copies the contents over, the same work the + loop did, but rarely, not every pass.

You do not manage capacity by hand for normal code. For a huge build, hint the starting size to skip some grow steps.

This starts a builder with room for 1000 characters up front.

StringBuilder big = new StringBuilder(1000); // reserve room for ~1000 chars

That is a small optimization. Most code can ignore capacity and just append.

⚖️ String vs StringBuilder: which to use

The rule is about how often the text changes.

  • Use a String for fixed or rarely changed text: names, labels, messages, a few joins. Simpler and safe to share.
  • Use a StringBuilder when you build or change text many times, especially in a loop. It avoids throwaway objects, so it is much faster.
  • For a couple of + joins, a String is fine and clearer. Save StringBuilder for heavy, repeated building.

The simple test

Ask yourself: does this text get built up over many steps, or is it set once? Built over many steps, especially in a loop, means StringBuilder. Set once means a plain String.

There is also a close cousin, StringBuffer:

  • Same job, same methods as StringBuilder.
  • It is thread-safe, so many threads can share one buffer safely; that check makes it a little slower.
  • Prefer StringBuilder for normal single-threaded code; use StringBuffer only when several threads truly share one buffer.

⚠️ Common Mistakes

A few StringBuilder slip-ups to watch for.

Using + in a big loop. This is the whole reason StringBuilder exists. In a heavy loop, + creates a throwaway String every pass.

// ❌ slow: a new String every pass
String out = "";
for (int i = 0; i < 100000; i++) out = out + i;
// ✅ fast: one buffer
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) sb.append(i);
String out = sb.toString();

Forgetting toString(). A StringBuilder is not a String. To store it in a String variable or print it as clean text, call toString().

StringBuilder sb = new StringBuilder("Hi");
// ❌ this is a StringBuilder, not the text you want to keep
String text = sb; // won't even compile
// ✅ convert it first
String text2 = sb.toString();

Expecting String methods on it. A StringBuilder does not have the full String toolbox, and its equals does not compare text. Convert to a String when you want String methods.

StringBuilder a = new StringBuilder("Hi");
StringBuilder b = new StringBuilder("Hi");
// ❌ equals here compares the objects, not the text -> false
System.out.println(a.equals(b));
// ✅ compare the text by converting first
System.out.println(a.toString().equals(b.toString())); // true

equals does not compare text

StringBuilder.equals() does not look at the characters inside. It checks if the two are the very same object. To compare the contents, call toString() on both and compare those Strings.

✅ Best Practices

Habits for using StringBuilder well.

  • Reach for it in loops. Whenever you build text across many passes, use a StringBuilder, not +.
  • Chain your appends. sb.append(a).append(b) reads cleanly and avoids extra lines.
  • Call toString() at the end. Convert to a String once, after you finish building.
  • Reuse a builder with setLength(0) if you need to start fresh inside the same method instead of making a new one.
  • Hint the size for huge builds with new StringBuilder(1000) when you already know it will be big.
  • Keep String for simple text. Do not over-engineer. A couple of joins do not need a builder.

🧩 What You’ve Learned

Let’s recap StringBuilder.

  • ✅ A StringBuilder is a changeable text buffer, unlike the immutable String.
  • ✅ It avoids creating throwaway Strings when you build text repeatedly, so it is faster in loops.
  • append() adds to the end and can be chained; insert, delete, deleteCharAt, replace, and reverse edit in place.
  • length(), setLength(), and capacity() help you size and trim the buffer.
  • ✅ Call toString() to turn the builder into a normal String.
  • StringBuffer does the same job but is thread-safe and a bit slower; prefer StringBuilder for normal code.
  • ✅ Use String for fixed text and StringBuilder for heavy, repeated building.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    Why is StringBuilder faster than String for building text in a loop?

    Why: String is immutable, so each + makes a new object; StringBuilder edits one buffer in place.

  2. 2

    What does the append() method do?

    Why: append adds text to the end of the same StringBuilder object.

  3. 3

    How do you turn a StringBuilder into a normal String?

    Why: toString() converts the builder's contents into a String.

  4. 4

    When is a plain String the better choice?

    Why: For simple, fixed text a String is clearer; StringBuilder is for heavy repeated building.

🚀 What’s Next?

You now know StringBuilder, the fast changeable way to build text. Next comes its thread-safe cousin, StringBuffer. It does the same job with the same methods, but it is built so many threads can share one buffer safely. Let’s look at it next.

Java StringBuffer

Share & Connect