Tuesday, November 28, 2006

String vs. StringBuffer

Thesis
Out of the following two ways to create a String, usage B is better and must be preferred over usage A.
Usage A:
String string = new StringBuffer("Left ").append(" Center ").append(" Right").toString();
Usage B:
String string = "Left " + " Center " + " Right";


Background
Wherever there is a need to concatenate long strings, I have seen several people based on their previous experience (!) insist to use StringBuffer. One of my colleagues, is so convinced, that he prefers to use StringBuffer even within the log messages. Now, I have always read that StringBuffer must be used when either there is a need to update the string or the actual string creation is required to be done at the runtime (for e.g. conditional creation of strings). This is because of the fact that String in Java is immutable, hence on every update a new String object needs to be created, thereby making the operation inefficient.

Even though having this feeling for a long time, I was not able to convince much people about this until I was given this link from a friend. After reading the blog, I thought of doing an analysis myself and here is what I found out.

Analysis
I created a following sample program to find out the variation in the generated byte code:

public class StringPerformanceTest {
public void useString() {
String string = "Left " + " Center " + " Right";
}

public void useStringBuffer() {
String string = new StringBuffer("Left ").append(" Center ").append(" Right").toString();
}
}


Here is the complete byte code of the program (using Java version 1.5.0_06):

public class StringPerformanceTest extends java.lang.Object{
public StringPerformanceTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return

public void useString();
Code:
0: ldc #2; //String Left Center Right
2: astore_1
3: return

public void useStringBuffer();
Code:
0: new #3; //class java/lang/StringBuffer
3: dup
4: ldc #4; //String Left
6: invokespecial #5; //Method java/lang/StringBuffer."":(Ljava/lang/String;)V
9: ldc #6; //String Center
11: invokevirtual #7; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
14: ldc #8; //String Right
16: invokevirtual #7; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
19: invokevirtual #9; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
22: astore_1
23: return

}


It is clear from the byte code that on using concatenation operator only 3 instructions will be called (useString), whereas on using StringBuffer number of instructions that shall be executed is much more (useStringBuffer). Besides, against the common thinking, only one object is created even while using concatenation operator.

Performance Concerns

When a String is created using concatenation operators, it is created at the compile time itself, whereas when the String is created using StringBuffer, the strings are created at run-time thereby hitting the performance when there is no need to create them at runtime. More the number of append() calls, more will be the performance hit.

Conclusion
It is better to create strings using concatenation rather than using StringBuffer for the same purpose.

2 comments:

  1. I know this is an old post but....

    Your code is not a good example. The compiler will optimize your String object result into a literal. A better example would be to create the String object then use the += operator and variables being appended to that object.

    ReplyDelete
  2. That's exactly my point. Compiler optimized +, hence it must be preferred over StringBuffer(Builder). However, there are people who use StringBuffer(Builder).

    StringBuffer(Builder) must be definitely preferred over +=.

    ReplyDelete