Today I was reading alibaba development manual taishan edition, and found such a clause in the development manual: [recommended] In the loop body, the way of connecting strings, using StringBuilder append method to expand.
Three representation types of strings
Type String
String is an immutable type. The following is the source code for the String class in JDK11. The member variables of String are value and hash. Value is a reference to an array object wrapped in String. Value is modified by private final, and there is no public method such as setValue to modify the value. So String is immutable.
public final class String
implements java.io.Serializable.Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
}
Copy the code
Every operation on a String that modifies the String generates a new String. The replace() function in the String class is called each time a String is modified and returns new String(buf, true); . Therefore, using strings to connect in the body of the loop is not only inefficient, but also a waste of memory resources.
/**
* Returns a string resulting from replacing all occurrences of
* {@code oldChar} in this string with {@code newChar}.
*
* @param oldChar the old character.
* @param newChar the new character.
* @return a string derived from this string by replacing every
* occurrence of {@code oldChar} with {@code newChar}.
*/
public String replace(char oldChar, char newChar) {
if(oldChar ! = newChar) {int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break; }}if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);// Generate a new String}}return this;
}
Copy the code
StringBuffer type
The StringBuffer class is a thread-unsafe mutable data type inherited from the AbstractStringBuilder class.
The following is the source of the StringBuffer class in JDK11. The StringBuffer class implements mutable character sequences such as append(), Insert (), delete(), replace(), charAt(), and so on. These methods are sychronized and thread-safe.
In cases where thread-safety or single-threading is not required, StringBuffers suffer performance losses due to thread locking, so using StringBuffe in the body of the loop is inefficient.
The StringBuilder type
StringBuilder is a thread-unsafe mutable data type. AbstractStringBuilder class, like StringBuffer class.
The following is the source of the StringBuffer class in JDK11. The StringBuffer class implements mutable character sequences such as append(), Insert (), delete(), replace(), charAt(), and so on. Unlike StringBuffer, these methods are not locked and cannot degrade performance, so StringBuilder is recommended in the manual.
Performance tests for String, StringBuilder, and StringBuffer
The test code is as follows:
/** * <p> Tests String, StringBuilder, and StringBuffer performance </p> **@author : cxc
* @date: the 2020-06-22 01:56 * * /
public class Test {
public static Runtime runtime = Runtime.getRuntime();
public static void main(String[] args) {
long maxMemory = runtime.maxMemory();
System.out.println("Maximum memory:" + maxMemory/1024/1024 + "M");
int [] times = {10000.100000.1000000.10000000.100000000.1000000000};
for (int i : times) {
System.out.println("Number of cycles:"+ i); StringTest(i); StringBuilderTest(i); StringBufferTest(i); System.out.println(); }}private static void StringTest(int times){
String sbd = "";
long start = System.currentTimeMillis();
while (sbd.length() < times) {
sbd += "a";
}
System.out.println("String execution time:" + (System.currentTimeMillis() - start)+"ms");
System.out.println("String uses memory:" + (runtime.totalMemory() - runtime.freeMemory())/1024/1024 + "M");
}
private static void StringBuilderTest(int times){
StringBuilder sbd = new StringBuilder();
long start = System.currentTimeMillis();
while (sbd.length() < times) {
sbd.append("a");
}
System.out.println("StringBuilder execution time:" + (System.currentTimeMillis() - start)+"ms");
System.out.println("StringBuilder uses memory:" + (runtime.totalMemory() - runtime.freeMemory())/1024/1024 + "M");
}
private static void StringBufferTest(int times){
StringBuffer sbf = new StringBuffer();
long start = System.currentTimeMillis();
while (sbf.length() < times) {
sbf.append("a");
}
System.out.println("StringBuffer execution time:" + (System.currentTimeMillis() - start)+"ms");
System.out.println("StringBuffer uses memory:" + (runtime.totalMemory() - runtime.freeMemory())/1024/1024 + "M"); }}Copy the code
The result is as follows: As the number of loops increases, the performance advantage of StringBuilder becomes more and more obvious in the body of the loop.
Blog.csdn.net/weixin_4110…