An attribute of the String
type is that they are immutable. This allows for a number of good attributes. Another attribute of the String
type is that Java provides some syntactic sugar to concatenate String
s by using the +
operator. This is a very beneficial ability but putting these two capabilities together, immutability and simple contenation can lead us to accidentally cause performance issues. Let's consider an example:
public String concatenateStrings(int numberOfIterations) {
String result = "";
for (int i=0; i < numberOfIterations; i++) {
result += randomStringOfLength(m);
}
return result;
}
With a low value for numberOfIterations
this can turn out to be fine. As the number of iterations goes up the cost goes up drastically. This is because the String
s can't be modified and must be copied. This not only costs a lot of compute power but also creates a lot of garbage for the garbage collector to clean up. Compare this to the much more performant version:
public String concatenateStrings(int numberOfIterations) {
StringBuilder result = new StringBuilder();
for (int i=0; i < numberOfIterations; i++) {
result.append(randomStringOfLength(m));
}
return result.toString();
}
This code uses a mutable holder to collect the String
s so it can concatenate them all at once.
So when should we use string concatenation and when should we use the StringBuilder
. A good rule of thumb is to use a StringBuilder
when concatenating in a loop. When concatenating a static number of String
s the performance won't get any better or worse from your initial testing so you won't be surprised by performance problems.
Top comments (2)
You might also want to initialize the size of the StringBuilder when you have a rough idea of the resulting size. In the above example
(Assuming numberOfIterations or m is not negative)
Yeah, you are exactly right. This is a great further optimization.