Thursday, February 10, 2011

String Vs StringBuilder

String Vs StringBuilder

Many time question comes into mind when to use String and when to use StringBuilder. Rule of thumb is that when you want to append the string it is best practice to use StringBuilder rather than appending the String object which is immutable.

Lets look at some example below lets to find out the performance difference between String and StringBuilder.

Testing String:

import java.util.Calendar;

public class StringTest {
public static void main(String[] args) {
long startTime = Calendar.getInstance().getTimeInMillis();
String test = "Testing";
test += "String";
test +="For Permormance";
test +="during append";
long endTime = Calendar.getInstance().getTimeInMillis();
System.out.println("Time Taken in Millisec ="+(endTime -startTime) + " to display String :" +test);
}
}

When you run that it the output will be :
Time Taken in Millisec =0 to display String :TestingStringFor Permormanceduring append


Testing StringBuilder:
import java.util.Calendar;

public class StringBuilderTest {

public static void main(String[] args) {

long startTime = Calendar.getInstance().getTimeInMillis();
StringBuilder testBuilder = new StringBuilder("Testing");
testBuilder.append("String");
testBuilder.append("For Permormance");
testBuilder.append("during append");
long endTime = Calendar.getInstance().getTimeInMillis();
System.out.println("Time Taken in Millisec ="+(endTime -startTime) + " to display String :" +testBuilder.toString());
}
}

When you run it the output will be:
Time Taken in Millisec =0 to display String :TestingStringFor Permormanceduring append

If you see the output in terms of performance is same for String and StringBuilder so question arise why not to use the String straightly rather then using the StringBuilder ?

Here is catch even when you are appending the String straightly compiler is smart enough to use the StringBuilder internally.

There is one tool javap - The Java Class File Disassembler which comes with the JDK lets use that try to find out JVM bytecode.

javap -c StringTest and the outcome will be:

public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method java/util/Calendar.getInstance:()Ljava/util/Calendar;
3: invokevirtual #3; //Method java/util/Calendar.getTimeInMillis:()J
6: lstore_1
7: ldc #4; //String Testing
9: astore_3
10: new #5; //class java/lang/StringBuilder
13: dup
14: invokespecial #6; //Method java/lang/StringBuilder."":()V
17: aload_3
18: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: ldc #8; //String String
23: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: astore_3
30: new #5; //class java/lang/StringBuilder
33: dup
34: invokespecial #6; //Method java/lang/StringBuilder."":()V
37: aload_3
38: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: ldc #10; //String For Permormance
43: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
49: astore_3
50: new #5; //class java/lang/StringBuilder
53: dup
54: invokespecial #6; //Method java/lang/StringBuilder."":()V
57: aload_3
58: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
61: ldc #11; //String during append
63: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
66: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
69: astore_3
70: invokestatic #2; //Method java/util/Calendar.getInstance:()Ljava/util/Calendar;
73: invokevirtual #3; //Method java/util/Calendar.getTimeInMillis:()J
76: lstore 4
78: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
81: new #5; //class java/lang/StringBuilder
84: dup
85: invokespecial #6; //Method java/lang/StringBuilder."":()V
88: ldc #13; //String Time Taken in Millisec =
90: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
93: lload 4
95: lload_1
96: lsub
97: invokevirtual #14; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
100: ldc #15; //String to display String :
102: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
105: aload_3
106: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
109: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
112: invokevirtual #16; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
115: return

}


If you are familiar with assembly language you can dig it further, but if you are not it is simple to interpret if you see for each String operation += the JVM had created a separate StringBuilder object and append the given String and again assign back to the String Object using the toString(). Please refer line no 14, 34 and 54.


Now lets do the same for StringBuilder
javap -c StringBuilderTest and the outcome will be:

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

public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method java/util/Calendar.getInstance:()Ljava/util/Calendar;
3: invokevirtual #3; //Method java/util/Calendar.getTimeInMillis:()J
6: lstore_1
7: new #4; //class java/lang/StringBuilder
10: dup
11: ldc #5; //String Testing
13: invokespecial #6; //Method java/lang/StringBuilder."":(Ljava/lang/String;)V
16: astore_3
17: aload_3
18: ldc #7; //String String
20: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: aload_3
25: ldc #9; //String For Permormance
27: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: pop
31: aload_3
32: ldc #10; //String during append
34: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
37: pop
38: invokestatic #2; //Method java/util/Calendar.getInstance:()Ljava/util/Calendar;
41: invokevirtual #3; //Method java/util/Calendar.getTimeInMillis:()J
44: lstore 4
46: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
49: new #4; //class java/lang/StringBuilder
52: dup
53: invokespecial #12; //Method java/lang/StringBuilder."":()V
56: ldc #13; //String Time Taken in Millisec =
58: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
61: lload 4
63: lload_1
64: lsub
65: invokevirtual #14; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
68: ldc #15; //String to display String :
70: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
73: aload_3
74: invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
77: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
80: invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
83: invokevirtual #17; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
86: return

}

You can clearly see that StringBuilder Object was created only Once at line no 13 and rest of the time append was called to append it to StringBuilder.

This is a very simple code and you can see the difference when you use String instead of StringBuilder the compiler had created StringBuilder object implicitly for 3 times and use toString call also for 3 times. And in case of StringBuilder it was only once. Object creation is expensive and if the code is bigger than there can be huge difference in case of performance and memory utilization.


Conclusion:

Use StringBuilder whenever you want to append the String.







No comments:

Post a Comment