If you are dynamically generating strings in your Java program, one of the best things you can do for your program is to build your string using a StringBuilder or StringBuffer, as opposed to using a regular old String.
The reason for this? In Java, strings are immutable, and every time you concatenate a string that the program hasn’t seen before, a new string object is created and stored in the heap. This means the whole process involves a lot of reading from and writing to the memory. The StringBuilder and StringBuffer in Java are objects that are designed to do string concatenation in a more efficient manner, but how much more?
We’ve got a simple Java program here that you can run from your browser so you can see it for yourself.
The program
This program that we wrote dynamically builds a string from A to Z using three different classes, and times how long each takes to complete:
StringStringBuilderStringBuffer
You can copy the program below, or run it on this online Java compiler here.
public class StringBuilderPerformanceTest {
public static void main(String args[]) {
System.out.println("Dynamically building a string from 'A' to 'Z' characters using a String, StringBuilder and StringBuffer...");
System.out.println();
// Measuring the time and memory for regular strings.
long startTime = System.nanoTime();
String s = "";
for(char c = 'A'; c <= 'Z'; c++) {
s += c;
}
long endTime = System.nanoTime();
System.out.printf("Regular string took %.3f milliseconds to compile.%n", (endTime - startTime) / 1000000.0);
// Measuring the time and memory for StringBuilder strings.
startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for(char c = 'A'; c <= 'Z'; c++) {
sb.append(c);
}
endTime = System.nanoTime();
System.out.printf("StringBuilder string took %.3f milliseconds to compile.%n", (endTime - startTime) / 1000000.0);
// Measuring the time and memory for StringBuffer strings.
startTime = System.nanoTime();
StringBuffer sbf = new StringBuffer();
for(char c = 'A'; c <= 'Z'; c++) {
sbf.append(c);
}
endTime = System.nanoTime();
System.out.printf("StringBuffer string took %.3f milliseconds to compile.%n", (endTime - startTime) / 1000000.0);
}
}
Here is the output of the program from running it on JDoodle (note that you will yield slightly different results every run):
Dynamically building a string from 'A' to 'Z' characters using a String, StringBuilder and StringBuffer... Regular string took 24.256 milliseconds to compile. StringBuilder string took 0.047 milliseconds to compile. StringBuffer string took 0.138 milliseconds to compile.
In other words…
- The
StringBuilderalgorithm finished its task about 500 times faster than theStringalgorithm. - The
StringBuilderis about 3 times faster than theStringBuffer.
Again, note that you may get slightly different results when you run the code yourself! But the StringBuilder and StringBuffer should always be miles faster than using String objects!
Difference between StringBuilder and StringBuffer
You will always want to use the StringBuilder over the StringBuffer in almost all instances, unless you are:
- Running a multi-thread program, and;
- Are building the string using multiple threads
This is because the StringBuffer is thread-safe. What this means is that StringBuffer objects can avoid race conditions — i.e. it will not allow 2 threads to update the StringBuffer at the same time.
