I believe that everyone has a good understanding of the difference between String and StringBuffer, but it is estimated that there are still many comrades who are not clear about the working principles of these two classes. Today I will review this concept for everyone, and by the way There is a new character operation class introduced in J2SE 5.0 - StringBuilder. So what are the differences between this StringBuilder and StringBuffer and the String class we first met? Which one should we use in different situations? I would like to share my views on these categories, and I also hope that everyone can give their opinions. Everyone has made mistakes, and while correcting them, it is a good opportunity to learn.
Briefly speaking, the main performance difference between the String type and the StringBuffer type is actually that String is an immutable object (Why? Ask the designers of Java, why is String not a native type?) Therefore, every time the String type is changed, In fact, it is equivalent to generating a new String object, and then pointing the pointer to the new String object. Therefore, it is best not to use String for strings that often change content. , because every time an object is generated, it will have an impact on system performance. Especially when there are too many unreferenced objects in the memory, the JVM's GC will start to work, and the speed will definitely be quite slow. Here is an example that is not very appropriate:
If this is the case, after the for loop is completed, if the objects in the memory have not been cleared by the GC, there will be more than 20,000 in the memory, an astonishing number, and if this is a system used by many people, then The number is not very large, so everyone must be careful when using it.
If you use the StringBuffer class, the results will be different. Each time the result will be an operation on the StringBuffer object itself, instead of generating a new object and then changing the object reference. So in general we recommend using StringBuffer, especially when string objects change frequently. In some special cases, the string concatenation of String objects is actually interpreted by the JVM as the concatenation of StringBuffer objects, so in these cases the speed of String objects will not be slower than that of StringBuffer objects, and especially the following string objects are generated Among them, String efficiency is much faster than StringBuffer:
You will be surprised to find that the speed of generating String S1 objects is simply too fast, and at this time StringBuffer does not have an advantage at all in speed. In fact, this is a trick of the JVM. In the eyes of the JVM, this
From this we get the first step conclusion: In most cases StringBuffer > String
And how does StringBuilder compare with them? Let me briefly introduce it first. StringBuilder is a newly added class in JDK5.0. The difference between it and StringBuffer is as follows (source: JavaWorld):
Java.lang.StringBuffer Thread-safe mutable character sequence. A string buffer similar to String, but cannot be modified. String buffers can be used safely by multiple threads. These methods can be synchronized when necessary, so that all operations on any particular instance appear to occur in a serial order consistent with the order of method calls made by each thread involved.
Each string buffer has a certain capacity. As long as the length of the character sequence contained by the string buffer does not exceed this capacity, there is no need to allocate a new internal buffer array. This capacity is automatically increased if the internal buffer overflows. Starting from JDK 5.0, an equivalent class for single thread use, StringBuilder, has been added to this class. The StringBuilder class should generally be used in preference to this class because it supports all the same operations but is faster because it does not perform synchronization.
But it is unsafe to use an instance of StringBuilder with multiple threads. If such synchronization is required, it is recommended to use StringBuffer.
With this said, I think everyone can understand the difference between them, so let's make a general derivation below:
In most cases StringBuilder > StringBuffer
Therefore, according to the transitive theorem of this inequality: In most cases StringBuilder > StringBuffer > String
Now that we have such derivation results, let’s do a test to verify:
The test code is as follows:
/** Creates a new instance of testssb */
final static int ttime = 10000;//Number of test loops
public testssb() {
}
public void test(String s){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s += "add";
}
long over = System.currentTimeMillis();
System.out.println("The time used by the operation "+s.getClass().getName()+" type is: " + (over - begin) + " milliseconds" );
}
public void test(StringBuffer s){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("add");
}
long over = System.currentTimeMillis();
System.out.println("The time used by the operation "+s.getClass().getName()+" type is: " + (over - begin) + " milliseconds" );
}
public void test(StringBuilder s){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("add");
}
long over = System.currentTimeMillis();
System.out.println("The time used by the operation "+s.getClass().getName()+" type is: " + (over - begin) + " milliseconds" );
}
// Directly test string concatenation on String
public void test2(){
String s2 = "abadf";
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
String s = s2 + s2 + s2 ;
}
long over = System.currentTimeMillis();
System.out.println("The time used to operate the string object reference addition type is: " + (over - begin) + " milliseconds" );
}
public void test3(){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
String s = "abadf" + "abadf" + "abadf" ;
}
long over = System.currentTimeMillis();
System.out.println("The time used to add operation strings is: "+ (over - begin) + " milliseconds" );
}
public static void main(String[] args){
String s1="abc";
StringBuffer sb1 = new StringBuffer("abc");
StringBuilder sb2 = new StringBuilder("abc");
testssb t = new testssb();
t.test(s1);
t.test(sb1);
t.test(sb2);
t.test2();
t.test3();
}
}
It seems that you still can't see the difference between StringBuffer and StringBuilder. Add ttime to 30000 times and see:
The time used to operate the java.lang.String type is: 53444 milliseconds The time used to operate the java.lang.StringBuffer type is: 15 milliseconds The time used to operate the java.lang.StringBuilder type is: 15 milliseconds The time used to operate the string object reference addition type Time taken: 31 milliseconds Addition of strings took time: 0 milliseconds
There is still not much difference in performance between StringBuffer and StringBuilder. Let’s increase it to 100000 and take a look. We won’t add the test for the String type here, because testing such a large amount of data for the String type will be very slow...
The time taken to operate the java.lang.StringBuffer type is: 31 milliseconds The time taken to operate the java.lang.StringBuilder type is: 16 milliseconds
You can see the difference, but many of the test results show that StringBuffer is faster than StringBuilder. Let's increase the value to 1000000 and see (it shouldn't crash, right?):
The time taken to operate the java.lang.StringBuffer type is: 265 milliseconds The time taken to operate the java.lang.StringBuilder type is: 219 milliseconds
There are less differences, and the results are very stable. Let’s look at it a little larger, ttime = 5000000:
・・・・・・ Exception in thread "main" java.lang.OutOfMemoryError: Java heap space ・・・・・・
Haha, forget it, I won’t test it anymore. Basically, the performance is StringBuilder > StringBuffer > String.