Why is this an issue?

Strings are immutable objects, so concatenation doesn’t simply add the new String to the end of the existing string. Instead, in each loop iteration, the first String is converted to an intermediate object type, the second string is appended, and then the intermediate object is converted back to a String. Further, performance of these intermediate operations degrades as the String gets longer. Therefore, the use of StringBuilder is preferred.

Noncompliant code example

String str = "";
for (int i = 0; i < arrayOfStrings.length ; ++i) {
  str = str + arrayOfStrings[i];
}

Compliant solution

StringBuilder bld = new StringBuilder();
  for (int i = 0; i < arrayOfStrings.length; ++i) {
    bld.append(arrayOfStrings[i]);
  }
  String str = bld.toString();

Resources

Benchmarks

Method size Runtime Average time Error margin

plus

100

Temurin 21

4.19 µs/op

±0.34 µs/op

plus

1000

Temurin 21

377.08 µs/op

±17.36 µs/op

plus

10000

Temurin 21

40221.49 µs/op

±1342.76 µs/op

plus

100000

Temurin 21

5286840.53 µs/op

±185796.75 µs/op

stringBuilder

100

Temurin 21

0.97 µs/op

±0.03 µs/op

stringBuilder

1000

Temurin 21

10.25 µs/op

±1.64 µs/op

stringBuilder

10000

Temurin 21

93.27 µs/op

±16.05 µs/op

stringBuilder

100000

Temurin 21

1019.91 µs/op

±69.58 µs/op

Benchmarking code

The results were generated by running the following snippet with JMH.

@Param({"100", "1000", "10000", "100000"})
int size;
private String word = "append";

@Benchmark
public String plus() {
  String str = "";
  for (int i = 0; i < size; i++) {
    str = str + word;
  }
  return str;
}

@Benchmark
public String stringBuilder() {
  StringBuilder builder = new StringBuilder();
  for (int i = 0; i < size; i++) {
    builder.append(word);
  }
  return builder.toString();
}