Java StringBuffer append allocation – Education Career Blog

When using StringBuffer in java, I’m wondering how the append function is implemented when it needs to reallocate space.

For example, if I append a string longer than the currently allocated space, how does it manage this in the details of the method?

,

The source is included in the JDK download. Just look for the src.zip file (mine is in Program Files (x86)\Java\jdk1.6.0_01\src.zip). After extracting, just go to java/lang and you can examine StringBuffer.java, StringBuilder.java, and AbstractStringBuilder.java.

In this implementation, looks like “expandCapacity” in AbstractStringBuilder calculates the capacity and does an Arrays.copyOf() to expand the buffer. It’s also interesting to note that first check is for < 0 to guard against overflow condition.

void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
    if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
    } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
    value = Arrays.copyOf(value, newCapacity);
}

,

The Apache Harmony implementation relies on the methods in AbstractStringBuilder to manage additions/deletions (StringBuffer extends AbstractStringBuilder).

AbstractStringBuilder keeps a character buffer (that is, an array of chars) to hold the current “string”. When appending the next string representation of any object to this buffer it checks if the buffer contains enough space, and if there’s not enough space it allocates a new character buffer, copies the old buffer, and then adds the new string to that buffer. We can glean that from the internals of enlargeBuffer:

private void enlargeBuffer(int min) {
    int newSize = ((value.length >> 1) + value.length) + 2;
    char newData = new charmin > newSize ? min : newSize;
    System.arraycopy(value, 0, newData, 0, count);
    value = newData;
    shared = false;
 }

…and this method is invoked in any append method when the capacity of value (the private member that holds the char buffer) would be exceeded:

final void append0(char chars) {
    int newSize = count + chars.length;
    if (newSize > value.length) {
         enlargeBuffer(newSize);
     }
     System.arraycopy(chars, 0, value, count, chars.length);
     count = newSize;
}

The standard OpenJDK implementation is pretty similar. Again, StringBuffer relies on AbstractStringBuilder:

void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
    if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
    } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
    value = Arrays.copyOf(value, newCapacity);
}

Note that Arrays.copyOf copies the character array value padding it with null characters to have total size newCapacity, which is basically equivalent to the new char... call in the Harmony approach. Again, similarly, the expandCapacity method is invoked when there’s not enough space to add the next string segment:

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
    int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
         expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
}

Leave a Comment