1. String immutability: friend or foe?
In Java, the String class is immutable. This means that after creation a string cannot be changed. Every time you “change” a string — for example, by appending something using + or concat() — a new object is actually created, and the old one is left for the garbage collector.
Example:
String s = "Hello";
s = s + " world!";
System.out.println(s); // Hello world!
It looks as if the string s changed, but in reality a new string "Hello world!" was created, while the old "Hello" stays in memory until the garbage collector removes it. If there are many such operations — for example, inside a loop — the program starts to slow down and waste extra memory.
Imagine you are building a tower out of blocks, and every time you want to add a new block you have to rebuild the entire tower from scratch. Not very efficient, right? That’s how a regular String in Java behaves under frequent modifications.
2. StringBuilder: a fast “builder” of strings
The StringBuilder class (package java.lang, no import needed) is a special tool for efficiently constructing and modifying strings. It is mutable: you can append, delete, and insert characters and substrings without creating a new object for each operation.
Analogy:
If String is a concrete slab, then StringBuilder is a LEGO set: add and remove pieces as much as you want without rebuilding everything from scratch.
How to create a StringBuilder
StringBuilder sb = new StringBuilder(); // empty
StringBuilder sb2 = new StringBuilder("Initial value");
Key methods
| Method | Description | Usage example |
|---|---|---|
|
Append a string, number, char, etc. to the end | |
|
Insert a value at the specified position | |
|
Remove characters from start (inclusive) to end (exclusive) | |
|
Replace part of the content with another substring | |
|
Reverse the sequence of characters | |
|
Convert to a regular String | |
|
Truncate or pad to the specified length | |
Example usage
StringBuilder sb = new StringBuilder();
sb.append("Hello, ");
sb.append("world!");
System.out.println(sb); // Hello, world!
sb.insert(7, "Java "); // insert "Java " after "Hello, "
System.out.println(sb); // Hello, Java world!
sb.replace(8, 12, "other"); // replace "Java" with "other"
System.out.println(sb); // Hello, other world!
sb.reverse();
System.out.println(sb); // !dlrow rehto ,olleH
3. StringBuffer: the older sibling with thread-safety
What’s the difference between StringBuilder and StringBuffer?
- StringBuilder is fast but not thread-safe (not synchronized).
- StringBuffer is slower but thread-safe (synchronized).
If your application runs in a single thread, use StringBuilder (faster). If multiple threads can modify the same string, use StringBuffer.
4. When should you use StringBuilder instead of String?
Scenarios
- Frequent string modifications (append, delete, insert) in a loop or when building large texts.
- Building a string from an array/list (CSV, HTML, reports, etc.).
- Parsing and processing text with a large number of string operations.
Example: building a string from an array
Bad approach (using String and +):
String[] names = {"Ivan", "Pyotr", "Maria"};
String result = "";
for (int i = 0; i < names.length; i++)
{
result += names[i];
if (i < names.length - 1)
{
result += ", ";
}
}
System.out.println(result);
Good approach (using StringBuilder):
String[] names = {"Ivan", "Pyotr", "Maria"};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < names.length; i++)
{
sb.append(names[i]);
if (i < names.length - 1)
{
sb.append(", ");
}
}
System.out.println(sb.toString());
Difference: in the first case a new string is created at each step; in the second we keep growing a single StringBuilder instance.
5. Performance comparison: String vs StringBuilder
// Using String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " ms");
// Using StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " ms");
Bottom line: in most cases, StringBuilder is orders of magnitude faster for repeated concatenations.
6. Useful details
Can you use String methods?
StringBuilder has its own methods. To get a string, call toString().
StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString(); // now s is a regular String
Can you compare StringBuilder via equals?
Careful: sb1.equals(sb2) compares references, not content. Compare like this:
if (sb1.toString().equals(sb2.toString()))
{
// contents match
}
Can you pass a StringBuilder to System.out.println?
Yes. System.out.println will call toString() automatically.
Can you read characters by index?
Yes, use charAt(int index), as with a regular string.
7. Common mistakes when working with StringBuilder and StringBuffer
Error No. 1: comparing two StringBuilder instances using equals or the == operator. These checks compare references, not content. Use toString() and compare Strings.
Error No. 2: forgetting to call toString() where a String is expected (method return, logging, passing to an API).
Error No. 3: using StringBuilder for a couple of simple concatenations. A form like "Hello, " + name is readable and efficient.
Error No. 4: concatenating a String in a loop using +. This is time- and memory-inefficient — use StringBuilder.
Error No. 5: confusing StringBuffer and StringBuilder without necessity. If there is no concurrent modification from multiple threads, choose StringBuilder.
Error No. 6: blindly truncating StringBuilder content with setLength(). Verify the new length; data beyond it will be lost.
GO TO FULL VERSION