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());
... the output is:
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
Consider how StringBuffer is typically used. When the String we need to store in a StringBuffer exceeds the current capacity, the current capacity is increased. If the algorithm only increased the capacity to the required amount, then StringBuffer would be very inefficient. For example:
buf.append(someText);
buf.append(someMoreText);
buf.append(Another100Chars);
might require that the capacity be increased three times in a row. Every time the capacity is increased, the underlying data structure (an array) needs to be re-allocated in memory, which involves allocating more RAM from the heap, copying the existing data, and then eventually garbage collecting the previously allocated memory. To reduce the frequency of this happening, StringBuffer will double its capacity when needed. The algorithm moves the capacity from n to 2n+2. Here is the source code from AbstraceStringBuilder 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 append to a StringBuffer or call setLength, this method is called:
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
}