Why does the following example change the capacity to 112?

In the following code ...

StringBuffer buf = new StringBuffer("Is is a far, far better thing that i do");
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());

buf.setLength(60);
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());

buf.setLength(30);
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());

      

... output:

buf = Is is a far, far better thing that i do 
buf.length() = 39
buf.capacity() = 55
buf = Is is a far, far better thing that i do
buf.length() = 60
buf.capacity() = 112
buf = Is is a far, far better thing 
buf.length() = 30
buf.capacity() = 112

      

+3


source to share


5 answers


Let's take a look at how StringBuffer is commonly used. When the String to be stored in the StringBuffer exceeds the current capacity, the current capacity is increased. If the algorithm were to increase the capacity to the required amount, then the StringBuffer would be very inefficient. For example:

 buf.append(someText);
 buf.append(someMoreText);
 buf.append(Another100Chars);

      

you may need to increase your bandwidth three times in a row. Each time the throughput increases, the underlying data structure (array) must be reallocated in memory, which involves allocating more RAM from the heap, copying existing data, and then removing garbage from the previously allocated memory. To reduce the frequency of this event, the StringBuffer will double its power when needed. The algorithm moves the capacity from n to 2n + 2. Here is the AbstraceStringBuilder source code where this method is implemented:



/**
 * This implements the expansion semantics of ensureCapacity with no
 * size check or synchronization.
 */
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);
}

      

Every time you add StringBuffer or call setLength this method is called:

public synchronized void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > value.length) {
        expandCapacity(minimumCapacity);
    }
}

      

+2


source


Call setLength(60)

will call call ensureCapacity(60)

1 .

ensureCapacity

relies on "doubling the array", which means that it (at least) doubles the capacity every time it needs to be increased. The exact definition is described in the Java Doc forensureCapacity

:

Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with more bandwidth. New capacity is larger:

  • The minimumCapacity argument.
  • Twice the old container plus 2.

If the minimumCapacity argument is not positive, this method takes no action and just returns.

In your specific case, the second expression (in bold) is larger than the requested capacity, so it will be used. Since 2 * 55 + 2 is equal to 112, there will be a new capacity.



Related question:

1) It will actually call extendCapacity, but it behaves the same as provide capacity.

+2


source


StringBuffer

calls the method at multiple points expandCapacity

. If it doesn't exceed the capacity, it will have to allocate a new array every time you change the value StringBuffer

. So this is some kind of performance optimization.

From the manual:

ensureCapacity

public void secureCapacity (int minimumCapacity)

Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with more capacity. New potential more:

* The minimumCapacity argument.
* Twice the old capacity, plus 2. 

      

If the minimumCapacity argument is not positive, this method takes no action and simply returns.

Parameters: minimumCapacity - the minimum desired capacity.

+2


source


This is a "read the free guide" case. From the Javadoc for StringBuffer -

public StringBuffer (String str)

Creates a string buffer initialized with the contents of the specified string. the initial capacity of the string buffer is 16 plus the length of the string argument.

which explains why he is originally 55. Then

public void secureCapacity (int minimumCapacity)

Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with more capacity. New potential more:

• The minimumCapacity argument.

• Twice old container plus 2.

If the minimumCapacity argument is non-positive, this method takes no action and simply returns.

explains why it changes to 112.

+1


source


public synchronized void setLength(int newLength) {
    super.setLength(newLength);
}

      

in super:

public void setLength(int newLength) {
    if (newLength < 0)
        throw new StringIndexOutOfBoundsException(newLength);
    ensureCapacityInternal(newLength);
....

      

Then:

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
....

      

Finally:

void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
....

      

0


source







All Articles