We must first remember the characteristics of three:
1. Definition
When looking at the API, you will find that String, StringBuffer, and StringBuilder all implement the CharSequence interface. Although they are all related to strings, their processing mechanisms are different.
2. Use scenarios
Scenarios using String class: In scenarios where strings do not change frequently, you can use String classes, such as declarations of constants and small number of variable operations.
Scenarios using the StringBuffer class: when string operations are frequently performed (such as splicing, substitution, deletion, etc.) and running in a multi-threaded environment, you can consider using StringBuffer, such as XML parsing, HTTP parameter parsing and encapsulation.
Scenarios using StringBuilder class: when string operations are frequently performed (such as splicing, substitution, and deletion), and running in a single-threaded environment, you can consider using StringBuilder, such as SQL statement assembly, JSON encapsulation, etc.
III. Analysis
To put it simply, the main performance difference between String type and StringBuffer type is actually that String is an immutable object, so every time you change the String type, it is actually 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 change content frequently, because each object generation will have an impact on system performance, especially when there are too many referenced objects in memory, the JVM's GC will start working, which will definitely be quite slow.
If you use the StringBuffer class, the result will be different. Each time the result will operate on the StringBuffer object itself, instead of generating a new object and then changing the object reference. Therefore, in general, we recommend using StringBuffer, especially when string objects are often changed. In some special cases, the string splicing of String objects is actually interpreted by the JVM as a splicing of StringBuffer objects. Therefore, the speed of String objects is not slower than StringBuffer objects at these times. Especially in the following string objects generation, String efficiency is much faster than StringBuffer:
String S1 = "This is only a" + "simple" + "test";StringBuffer Sb = new StringBuilder("This is only a").append("simple").append("test");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 any advantage in speed. In fact, this is a trick of the JVM. In the eyes of the JVM, this
String S1 = "This is only a" + "simple" + "test";
Actually:
String S1 = "This is only a simple test";
So of course it doesn't take much time. But what you should note here is that if your string comes from another String object, the speed is not that fast, for example:
String S2 = "This is only a";String S3 = "simple";String S4 = "test";String S1 = S2 +S3 + S4;
At this time, the JVM will do it in a regular manner in the original way.
4. In-depth optimization and processing of JVM
Is there really the above performance cost? String splicing is so common, is there no special processing optimization? The answer is that this optimization is performed when compiling .java to bytecode in JVM.
If a Java program wants to run, it will take two periods, compile time and run time. At compile time, the Java JVM (Compiler) converts the java file into bytecode. At runtime, the Java virtual machine (JVM) runs the compile-time generated bytecode. Through these two periods, Java has achieved the so-called compilation and running everywhere.
Let's experiment with what optimizations were made during the compilation period, and we create a piece of code that may have performance costs.
public class Concatenation { public static void main(String[] args) { String userName = "Andy"; String age = "24"; String job = "Developer"; String info = userName + age + job; System.out.println(info); }}Compile Concatenation.java. Get Concatenation.class
javac Concatenation.java
Then we use javap to decompile the compiled Concatenation.class file. javap -c Concatenation. If the javap command is not found, please consider adding the directory where the javap is located to the environment variable or using the full path of javap.
17:22:04-androidyue~/workspace_adt/strings/src$ javap -c ConcatenationCompiled from "Concatenation.java"public class Concatenation { public Concatenation(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String Andy 2: store_1 3: ldc #3 // String 24 5: store_2 6: ldc #4 // String Developer 8: store_3 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 16: aload_1 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: aload_2 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: aload_3 25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 31: store 4 33: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 36: aload 4 38: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 41: return}Among them, ldc, store, etc. are java bytecode instructions, similar to assembly instructions. The following comments use Java-related content for explanation. We can see that there are many StringBuilders on it, but we call them in Java code without display. This is the optimization made by JavaJVM. When JavaJVM encounters string splicing, a StringBuilder object will be created. The splicing behind it is actually calling the append method of the StringBuilder object. In this way, there will be no problems we are worried about.
5. Rely on JVM optimization alone?
Since the JVM has helped us optimize, is it enough to rely solely on JVM optimization? Of course not.
Let's look at a piece of code that has not been optimized for low performance
public void implicitUseStringBuilder(String[] values) { String result = ""; for (int i = 0 ; i < values.length; i ++) { result += values[i]; } System.out.println(result);}Compile with javac and view with javap
public void implicitUseStringBuilder(java.lang.String[]); Code: 0: ldc #11 // String 2: store_2 3: iconst_0 4: istore_3 5: iload_3 6: aload_1 7: arraylength 8: if_icmpge 38 11: new #5 // class java/lang/StringBuilder 14: dup 15: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 18: aload_2 19: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 22: aload_1 23: iload_3 24: aaload 25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 28: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 31: store_2 32: iinc 3, 1 35: goto 5 38: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 41: aload_2 42: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 45: return
Among them 8: if_icmpge 38 and 35: goto 5 form a loop. 8: if_icmpge 38 means that if the integer comparison of the JVM operand stack is greater than or equal to (i < the opposite result of values.length), it will jump to line 38 (System.out). 35: goto 5 means jumping directly to line 5.
But there is a very important thing here that StringBuilder object creation occurs between loops, which means that how many times the loops will create multiple StringBuilder objects, which is obviously not good. Naked low-level code.
Optimize it slightly to instantly improve the quality.
public void explicitUseStringBuilder(String[] values) { StringBuilder result = new StringBuilder(); for (int i = 0; i < values.length; i ++) { result.append(values[i]); }}Corresponding compiled information
11: aload_1 12: arraylength 13: if_icmpge 30 16: aload_2 17: aload_1 18: iload_3 19: aaload 20: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 23: pop 24: iinc 3, 1 27: goto 10 30: return
As can be seen from above, 13: if_icmpge 30 and 27: goto 10 form a loop loop, while 0: new #5 is outside the loop, so StringBuilder is not created multiple times.
In general, we need to try to avoid implicit or explicit creation of StringBuilders in the loop body. Therefore, those who understand how the code is compiled and how it is executed internally have relatively high code levels.
6. Conclusion
In most cases StringBuffer > String
Java.lang.StringBuffer is a thread-safe sequence of variable characters. A String-like string buffer, but cannot be modified. Although it contains a certain sequence of characters at any point in time, the length and content of the sequence can be changed by some method calls. String buffers can be used safely in programs for multithreading. And these methods can be synchronized when necessary, so all operations on any particular instance seem to occur in a serial order that is consistent with the order of method calls made by each thread involved.
The main operations on StringBuffer are the append and insert methods, which can be overloaded to accept any type of data. Each method can effectively convert the given data into a string, and then append or insert the characters of that string into the string buffer. The append method always adds these characters to the end of the buffer; the insert method adds characters at the specified point.
For example, if z refers to a string buffer object whose current content is "start", this method call z.append("le") will make the string buffer contain "startle" (accumulated); and z.insert(4, "le") will change the string buffer to contain "starlet".
In most cases StringBuilder > StringBuffer
java.lang.StringBuilder A variable character sequence is new in JAVA 5.0. This class provides a StringBuffer-compatible API, but is not guaranteed to be synchronized, so the usage scenario is single threaded. This class is designed to be a simple replacement for StringBuffer, when string buffers are used by a single thread (this is common). If possible, it is recommended to take this class first, as it is faster than StringBuffer in most implementations. The usage methods of both are basically the same.