Recently in the book "How Tomcat Works", there is a code like this:
public void Parse () { //Read a set of characters from the socket stringbuffer request = new StringBuffer (2048);
int i; byte[] buffer = new byte[2048];
Since I'll start with StringBuffer, it's always been
StringBuffer sb = new StringBuffer () sb.append ("SB") Sb.append ("another SB") Sb.append ("Just use StringBuffer to improve performance, whatever it is. ");
The key point is in the StringBuffer constructor.
If you do not pass any parameters, the default value of capacity is 16.
If you pass a value of type int, assign this value to capacity.
If a string is passed, the value of capacity is +16 of the length of the string.
StringBuffer passed capacity to its parent class Abstractstringbuilder, what did its parent do with capacity?
/** * The value is used for character storage. */char[] value;/** * The count is the number of characters used. */int count;
Abstractstringbuilder (int capacity) { value = new char[capacity]; }
is a new array of type char.
*************************************************************************************************************** ***************************************************
Focus on the Append method of StringBuffer. Suppose the code is new StringBuffer ("abc"); Look at line 140 and call the Append method inside the constructor.
StringBuffer calls the Append method of the parent class:
@Override public synchronized stringbuffer append (String str) { tostringcache = null; Super.append (str); return this; }
Public Abstractstringbuilder append (String str) { if (str = = null) return appendnull (); int len = Str.length (); Ensurecapacityinternal (count + len); Str.getchars (0, Len, value, count); Count + = Len; return this; }
Note that count has not been assigned, at this time count=0. If StringBuffer sb = new StringBuffer (); Sb.append ("SB"); In this case, the value of Count is also 0. As long as the first call to the Append,count value is 0. Let's say that the initial string we passed in is "ABC". Then the Count+len here is 3.
private void ensurecapacityinternal (int minimumcapacity) { //overflow-conscious code if (Minimumcapacity- Value.length > 0) expandcapacity (minimumcapacity); }
3-19<0 so does not call expandcapacity (minimumcapacity);
But when we append a string with a length of 17 again. Count+len=3+17=20. This will call Expandcapacity (minimumcapacity);
void expandcapacity (int minimumcapacity) { int newcapacity = value.length * 2 + 2; if (newcapacity-minimumcapacity < 0) newcapacity = minimumcapacity; if (Newcapacity < 0) { if (minimumcapacity < 0)//overflow throw new OutOfMemoryError (); newcapacity = Integer.max_value; } Value = arrays.copyof (value, newcapacity); }
As you can see, the purpose of this method is to enlarge the load.
Popular Point says, I have 3 apples, want to buy a basket to install. The JDK helped me make a basket of 19 apples according to my situation. If I had not had an apple at first, the JDK would have made me a basket that could fit 16 apples.
3 apples have been installed in the basket. Now I have 17 apples, and this basket is not fit.
The JDK tries to expand the capacity of the basket to twice times +2 of its existing capacity, which is fine if it can be loaded. If it is not finished, change the capacity to just the sum of the existing and available apples.
Note why this is always judged to be less than 0. Because newcapacity = value.length * 2 + 2; Minimumcapacity = count + len; Two of them are calculated by calculation. The number of int will overflow if it is too large, and the result after overflow is negative. Overflow when the highest bit is 1, that is, the sign bit is 1, but not negative.
You can see the copy action of an array when the load is expanded. There are several lines of code in the expandcapacity.
Summarize:
If the value of a string or int is not passed at new StringBuffer, then the value of capacity will be the default of 16. The chances of calling Expandcapacity later append a string are quite large, there are several lines of code in this method, and there are copies of the array. If the string length of each append is similar, then no value can be passed. But if append string is longer than once, suddenly the length of a string is very large. This time capacity is the length of the string, and then append once more, capacity will increase by twice times. There is a good chance that there will be a waste.
Capacity will frequently call expandcapacity, the increase may appear wasteful.
Suggestions:
When using StringBuffer, you should have a pre-judgment on the length of the final string, and then pass in the value of capacity. This avoids wasting and frequently expanding capacity. Not really, capacity in one of the append string length of the largest one to calculate.
Do you really want to use StringBuffer?