StringBuilder and StringBuffer in Java - Quiz
Total: 6 questions
1. What is the difference between String, StringBuilder and StringBuffer in Java?
What is the difference between String, StringBuilder and StringBuffer in Java?
String is immutable: every "modification" creates a new object. StringBuilder and StringBuffer are mutable — append(), insert(), delete(), replace() and reverse() change the contents of the same object.
The only difference between StringBuilder and StringBuffer is that StringBuffer methods are synchronized (thread-safe) and StringBuilder methods are not. That is why StringBuilder is faster in single-threaded code and is the default choice. StringBuffer has existed since Java 1.0, StringBuilder was added in Java 5.
All three classes are final, implement CharSequence and live in the java.lang package, so no import is needed. String.equals() compares contents, while StringBuilder and StringBuffer compare references.
2. Why is concatenation with += in a loop slower than StringBuilder, and do you need StringBuilder for a single expression like "Hello, " + name?
Why is concatenation with += in a loop slower than StringBuilder, and do you need StringBuilder for a single expression like "Hello, " + name?
In a loop, s += part creates a new String on every iteration and copies all the accumulated text into it — for n iterations that is about n²/2 copied characters. StringBuilder appends characters to one and the same buffer, so the work grows linearly:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
sb.append(i);
}
System.out.println(sb); // 01234
A single expression does not need an explicit StringBuilder: up to and including Java 8 the compiler turned + into an append() chain itself, and since Java 9 (JEP 280) it uses invokedynamic and StringConcatFactory. That is why IntelliJ IDEA shows the inspection "StringBuilder can be replaced with String". This optimization does not help inside a loop, and the StringBuilder must be created once before the loop, not inside it.
3. What is the difference between length() and capacity() in StringBuilder, and how does the internal buffer grow?
What is the difference between length() and capacity() in StringBuilder, and how does the internal buffer grow?
length() returns the number of characters currently stored, capacity() returns the size of the internal buffer, which is never smaller than the length. StringBuilder has no size() method.
The initial capacity depends on the constructor: new StringBuilder() — 16, new StringBuilder(int capacity) — the given number, new StringBuilder(String str) — str.length() + 16. For example, for "Hello" length = 5 and capacity = 21.
When the buffer overflows it roughly doubles (old capacity * 2 + 2, but not less than required): an empty builder gets capacity 34 after 17 characters are appended. If the final size is known in advance, pass it to the constructor; spare capacity can be released with trimToSize(). A trap: new StringBuilder('a') calls the int constructor and creates an empty object with capacity 97.
4. How do you correctly compare two StringBuilder objects by content?
How do you correctly compare two StringBuilder objects by content?
StringBuilder and StringBuffer do not override equals() and hashCode(), so sb1.equals(sb2) compares references and returns false even for identical text. Correct ways:
sb1.toString().equals(sb2.toString()); // true
sb1.compareTo(sb2) == 0; // true, Java 11+
"Hello".contentEquals(sb1); // String vs StringBuilder
Since Java 11, StringBuilder and StringBuffer implement Comparable, so they can be compared with compareTo() and sorted. For the same reason (no content-based equals()/hashCode()) a StringBuilder should not be used as a HashMap key or a HashSet element — store sb.toString() instead.
5. Does StringBuffer synchronization make any sequence of calls thread-safe?
Does StringBuffer synchronization make any sequence of calls thread-safe?
No. StringBuffer methods are synchronized, but that protects only a single call. A compound operation executed by two threads can still race:
if (sb.length() > 0) sb.append(", ");
Between the length() check and the append() call another thread may change the buffer. Such operations need external synchronization; more often it is simpler to give each thread its own StringBuilder. StringBuilder is safe in a multithreaded application as long as the object lives inside one method or one thread; StringBuffer is needed only when several threads modify the same object at the same time. It is not marked @Deprecated, but it is rarely used in new code.
6. How do you add text to the beginning of a StringBuilder, and how do you repeat a string several times?
How do you add text to the beginning of a StringBuilder, and how do you repeat a string several times?
Java has no prepend() method: to add text at the beginning, use insert(0, value). A valid offset for insert() is from 0 to length() inclusive, otherwise a StringIndexOutOfBoundsException is thrown.
StringBuilder sb = new StringBuilder("I like Java!");
sb.insert(0, ">> ");
System.out.println(sb); // >> I like Java!
System.out.println(new StringBuilder().repeat("=", 10)); // ========== (Java 21+)
Calling insert(0, ...) repeatedly in a loop shifts all characters each time and is as slow as +=: it is better to append() and call reverse() once, or build the parts in a different order. The repeat(str, count) method was added in Java 21 and appends a string or a character count times; a negative count throws IllegalArgumentException.