Performance Comparison of String and StringBuilder in Java Loops
The article presents a series of Java benchmarks that compare per‑iteration and cumulative string concatenation using String versus StringBuilder, explains why the compiler optimises String concatenation to StringBuilder, and draws conclusions about the most efficient usage patterns in loop‑heavy code.
The author investigates the common belief that StringBuilder is always faster than String for concatenation by designing a set of micro‑benchmarks in Java.
Test case 1 (per‑iteration concatenation): In each loop iteration a few fields are concatenated into a new string. Two variants are implemented – one using plain String concatenation and another using an explicit StringBuilder . The relevant methods are:
public static void useString() {
for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {
String str = str1 + i + str2 + i + str3 + i + str4;
}
}
public static void useStringBuilder() {
for (int i = 0; i < CYCLE_NUM_BIGGER; i++) {
StringBuilder sb = new StringBuilder();
String s = sb.append(str1).append(i).append(str2).append(i)
.append(str3).append(i).append(str4).toString();
}
}Test case 2 (cumulative concatenation): A single string is built over many iterations. Again both String and StringBuilder variants are provided, but the StringBuilder instance is created once outside the loop:
public static void useStringSpliceOneStr() {
String str = "";
for (int i = 0; i < CYCLE_NUM_LOWER; i++) {
str += str1 + str2 + str3 + str4 + i;
}
}
public static void useStringBuilderSpliceOneStr() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < CYCLE_NUM_LOWER; i++) {
sb.append(str1).append(str2).append(str3).append(str4).append(i);
}
}Each benchmark sleeps for 2 seconds before running, performs five warm‑up iterations, then measures five runs and reports the average time. The driver method is:
public static int executeSometime(int kind, int num) throws InterruptedException {
Thread.sleep(2000);
int sum = 0;
for (int i = 0; i < num + 5; i++) {
long begin = System.currentTimeMillis();
switch (kind) {
case 1: useString(); break;
case 2: useStringBuilder(); break;
case 3: useStringSpliceOneStr(); break;
case 4: useStringBuilderSpliceOneStr(); break;
default: return 0;
}
long end = System.currentTimeMillis();
if (i > 5) sum += (end - begin);
}
return sum / num;
}Results and analysis: In the first group both String and StringBuilder show identical performance because the Java compiler rewrites the String concatenation into a StringBuilder operation (verified with javap -c ). In the second group the StringBuilder version is dramatically faster; the String version suffers from creating a new StringBuilder on every iteration and converting it back to a String each time.
Additional experiments compared resetting a long‑lived StringBuilder (using setLength(0) or delete(0, sb.length()) ) with repeatedly allocating a new instance. Surprisingly, the reset approach was slower, suggesting that object allocation is cheaper than the extra method calls needed to clear the buffer.
Conclusion: The Java compiler already optimises simple String concatenation to use StringBuilder , so for per‑iteration concatenation the two approaches have the same speed. For scenarios that build a large string over many iterations, a single long‑lived StringBuilder is far more efficient because it avoids repeated allocations and conversions. Developers should therefore prefer a reusable StringBuilder when concatenating inside a loop, but can safely use the more readable String concatenation syntax for one‑off concatenations.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.