Title:
Find string concatenation performance using different ways of string concatenation.Experiment details
Following are the details of the environment.- Operating System: Linux version 2.6.28-19-generic
- Processor
- model name : Intel(R) Xeon(R) CPU 5140 @ 2.33GHz
- stepping : 6
- cpu MHz : 2327.593
- cache size : 4096 KB
- JVM
- java version : "1.6.0_13"
- Memory:
- MemTotal: 3094916 kB
Method
- Create an array of 5000/ 10000 String objects.
- Calculate the start time before staring the concatenation operation.
- Write a loop to concatenate all these objects using various ways (.concat method of String class, using StringBuffer, using StringBuilder, using + operator)
- Calculate the end time after concatenation operation.
- A Java program that was used to calculate the metrics is at the end of this document.
Terminology
Iterations - Number of times the process of concatenation is performed during the execution of the program.Operations - Number of concatenation operations done (5000/10000).
Observations
Following charts provide data for two different set of experiment.- Multiple iterations - 10, 100, 1000 iterations
- Multiple operations - 5000/ 10000 operations
Here are the graphs that show the performance of each of the concatenation operation.
- It is observed that wrong usage of StringBuilder requires largest time to perform operation.
- Using + sign to concatenate performs second worst.
- Using String.concat() method performs relatively better than using + sign.
- Contradictory to traditional belief the usage of StringBuffer does not cause any issues. It performs as well as using StringBuilder.
- It is important to understand that StringBuilder should be used in one shot. One call to StringBuilder.append() method is the right way to concatenate strings.
Conclusion
- StringBuilder and StringBuffer perform in the same way when used in the right fashion.
- Wrong usage of StringBuilder can cause severe performance penalties.
Tip
- StringBuilder should be used when only one thread is going to perform concatenation operation.
- StringBuffer should be used when multiple threads are going to perform concatenation operation.
Further Experiments
* Calculate memory usage while performing the same experiments.Ref:
* StringBuffer
Program
Here is the program that I used to get above metrics. One needs to provide different arguments to this program while running to have different iterations. One can update the value of variable limit to change the number of operations. In this program, currently the limit is set to 5000.
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
/**
*
* @author Shilpa Deshpande
*
*/
public class StringConcatenationPerformanceMeasurer {
private final int iteration;
private final String fileName;
class Measurement{
private long concat, plus, wrongBuilder, rightBuilder, stringBuffer;
/**
* @return The concat
*/
public long getConcat() {
return concat;
}
/**
* @param concat The concat to set
*/
public void setConcat(long concat) {
this.concat = concat;
}
/**
* @return The plus
*/
public long getPlus() {
return plus;
}
/**
* @param plus The plus to set
*/
public void setPlus(long plus) {
this.plus = plus;
}
/**
* @return The wrongBuilder
*/
public long getWrongBuilder() {
return wrongBuilder;
}
/**
* @param wrongBuilder The wrongBuilder to set
*/
public void setWrongBuilder(long wrongBuilder) {
this.wrongBuilder = wrongBuilder;
}
/**
* @return The rightBuilder
*/
public long getRightBuilder() {
return rightBuilder;
}
/**
* @param rightBuilder The rightBuilder to set
*/
public void setRightBuilder(long rightBuilder) {
this.rightBuilder = rightBuilder;
}
/**
* @return The stringBuffer
*/
public long getStringBuffer() {
return stringBuffer;
}
/**
* @param stringBuffer The stringBuffer to set
*/
public void setStringBuffer(long stringBuffer) {
this.stringBuffer = stringBuffer;
}
}
/**
* @param fileName
* @param iteration
*
*/
public StringConcatenationPerformanceMeasurer(int iteration, String fileName) {
this.iteration = iteration;
this.fileName = fileName;
}
/**
* @param args
*/
public static void main(String[] args) {
int iteration = 10;
String fileName = "StringConcatenationMeasurement.xls";
try {
System.out.println("Please enter number of iterations.");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String readLine = in.readLine();
iteration = Integer.valueOf(readLine);
}
catch (IOException e) {
e.printStackTrace();
}
StringConcatenationPerformanceMeasurer instance = new StringConcatenationPerformanceMeasurer(
iteration, fileName);
try {
instance.checkStringConcatenationPerformance();
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* @throws Exception
*
*/
public void checkStringConcatenationPerformance() throws Exception {
ArrayList measurementList = new ArrayList();
for (int k = 0; k < iteration; k++) {
int limit = 5000;
String[] array = new String[limit];
for (int i = 0; i < limit; i++) {
array[i] = "e" + i + " ";
}
// Native String Concatenation using concat method
long t0 = System.currentTimeMillis();
String sbS = "";
for (int i = 0; i < limit; i++) {
sbS = sbS.concat(array[i]);
}
long t1 = System.currentTimeMillis();
//System.out.println("Final String using concat " + sbS);
sbS = null;
// Wrong String concatenation using StringBuilder
StringBuilder sb = new StringBuilder();
sbS = "";
for (int i = 0; i < limit; i++) {
sbS = (sb.append(sbS).append(array[i])).toString();
sb = new StringBuilder();
}
long t2 = System.currentTimeMillis();
//System.out.println("Final String - wrong usage of StringBuilder " + sbS);
sbS = null;
// Right String concatenation using StringBuilder
sb = new StringBuilder();
for (int i = 0; i < limit; i++) {
sb.append(array[i]);
}
sbS = sb.toString();
//System.out.println("Final String - right usage of StringBuilder " + sbS);
long t3 = System.currentTimeMillis();
sbS = null;
// String concatenation using +
sbS = "";
for (int i = 0; i < limit; i++) {
sbS = sbS + array[i];
}
long t4 = System.currentTimeMillis();
//System.out.println("Final String using + " + sbS);
sbS = null;
// String concatenation using StringBuffer
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < limit; i++) {
buffer.append(array[i]);
}
sbS = buffer.toString();
//System.out.println("Final String using StringBuffer " + sbS);
long t5 = System.currentTimeMillis();
sbS = null;
System.out.println("=================================");
System.out.println("Native String Concatenation using concat method (Time in Milliseconds) " + (t1 - t0));
System.out.println("Wrong String concatenation using StringBuilder (Time in Milliseconds) " + (t2 - t1));
System.out.println("Right String concatenation using StringBuilder (Time in Milliseconds) " + (t3 - t2));
System.out.println("String concatenation using + (Time in Milliseconds) " + (t4 - t3));
System.out.println("String concatenation using StringBuffer (Time in Milliseconds) " + (t5 - t4));
System.out.println("=================================");
Measurement mm = new Measurement();
mm.setConcat((t1-t0));
mm.setWrongBuilder((t2-t1));
mm.setRightBuilder((t3-t2));
mm.setPlus((t4-t3));
mm.setStringBuffer((t5-t4));
measurementList.add(mm);
}
}
}
.




No comments:
Post a Comment