Home  >  Article  >  Java  >  How to use Java's StringBuilder correctly in high-performance scenarios

How to use Java's StringBuilder correctly in high-performance scenarios

WBOY
WBOYforward
2023-05-12 13:07:06650browse

Correct usage of StringBuilder in high-performance scenarios

About StringBuilder, most students only simply remember that you should use StringBuilder for string splicing, do not use +, and do not use StringBuffer, and then the performance will be the best. Yes, really?

Some students have also heard three specious experiences:

1. Java compiled and optimized + has the same effect as StringBuilder;

2. StringBuilder It is not thread-safe. For the sake of "safety", it is better to use StringBuffer;

3. Never splice the string of log information yourself, leave it to slf4j.

1. The initial length is so important that it deserves to be mentioned four times.

StringBuilder has a char[] inside, and constant append() is the process of constantly filling in char[].

The default length of char[] when using new StringBuilder() is 16. Then, what should I do if I want to append the 17th character?

Use System.arraycopy to double copy and expand the capacity! ! ! !

In this way, there is the cost of array copy, and secondly, the original char[] is also wasted and will be lost by GC. As you can imagine, a 129-character string has been copied and discarded four times, 16, 32, 64, and 128, and a total of 496 characters have been applied for an array. In a high-performance scenario, this is almost unbearable.

So, how important it is to set an initial value reasonably.

But what if I really can’t estimate well? It's better to overestimate. As long as the string is larger than 16 in the end, even if it's a little wasted, it's better than doubling the capacity.

2. Liferay's StringBundler class

Liferay's StringBundler class provides another idea for length setting. It does not rush to stuff things into char[] when append(). Instead, first take a String[] and store them all, and finally add up the lengths of all Strings to construct a StringBuilder of reasonable length.

3. However, double the char[] is still wasted

The waste occurs in the last step, StringBuilder.toString()

// Create a copy , don't share the array
return new String(value, 0, count);

String's constructor will use System.arraycopy() to copy the incoming char[] To ensure security and immutability, if the story ends like this, the char[] in StringBuilder will still be sacrificed in vain.

In order not to waste these char[], one way is to use various black technologies such as Unsafe to bypass the constructor and directly assign a value to the char[] attribute of String, but few people do this.

Another more reliable method is to reuse StringBuilder. Reuse also solves the previous length setting problem, because even if the estimate is not accurate at the beginning, it will be enough after a few more expansions.

4. Reuse StringBuilder

This method comes from the BigDecimal class in the JDK (it’s okay to see how important the JDK code is). SpringSide extracts the code into StringBuilderHolder, which has only one function

public StringBuilder getStringBuilder() {
sb.setLength(0);
return sb;
}

StringBuilder.setLength() function only resets Its count pointer and char[] will continue to be reused, and toString() will also pass the current count pointer as a parameter to the String constructor, so there is no need to worry about passing in old content that exceeds the size of the new content. . It can be seen that StringBuilder is completely reusable.

In order to avoid concurrency conflicts, this Holder is generally set to ThreadLocal. For standard writing methods, see the comments of BigDecimal or StringBuilderHolder.

5. + and StringBuilder

String s = “hello ” user.getName();

The effect of this sentence after javac compilation, It is indeed equivalent to using StringBuilder, but without setting the length.

String s = new StringBuilder().append(“hello”).append(user.getName());

However, if it is like the following:

String s = “hello ”;
// separated by some other statements
s = s + user.getName();

Each statement , will generate a new StringBuilder. There are two StringBuilders here, and the performance is completely different. If s =i; is in the loop body, it will be even more ridiculous.

According to R University, the hard-working JVM engineers are in the run optimization stage. According to XX: OptimizeStringConcat (opened by default after JDK7u40), it will be possible to combine adjacent (without control statements) StringBuilder into one. Try hard to guess the length.

So, to be on the safe side, continue to use StringBuilder and set the length yourself.

6. StringBuffer and StringBuilder

StringBuffer and StringBuilder both inherit from AbstractStringBuilder. The only difference is that StringBuffer functions have the synchronized keyword.

For those students who say that StringBuffer is "safe", when have you actually seen several threads take turns appending a StringBuffer? ? ?

7. Always hand over log string concatenation to slf4j??

logger.info("Hello {}", user.getName());

For logs that you don’t know whether to output, leaving it to slf4j to splice them only when they really need to be output can indeed save costs.

But for logs that must be output, it is faster to use StringBuilder to splice them yourself. Because looking at the implementation of slf4j, it is actually just constant indexof("{}"), constant subString(), and continuous use of StringBuilder to put it together. There is no silver bullet.

PS. The StringBuilder in slf4j reserves 50 characters outside the original Message. If the variable parameters add up to more than 50 characters, they still have to be copied and expanded... and the StringBuilder is not reused.

The above is the detailed content of How to use Java's StringBuilder correctly in high-performance scenarios. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete