Name: nt126004 Date: 11/08/2001
java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)
It's a very common Java idiom to append text to a StringBuffer and then return
the corresponding String using the StringBuffer's "toString()" method. When
using a StringBuffer it is common (and good practice) to set the length of the
StringBuffer ahead of time to prevent the StringBuffer from continuously
allocating progressively larger char arrays which must then be GCed.
If you do *not* pre-set the length of a StringBuffer you end up with a default
length of 16 characters.
Here's the problem: If you create a String from a StringBuffer and then you
later set the length of the StringBuffer to zero, the internal size of the
StringBuffer's char[] shrinks down to the default 16 characters, essentially
undoing the capacity setting. Here's an example:
public class Tester {
static StringBuffer sb = new StringBuffer(1024);
public static void main(String[] args) {
System.out.println("length:" + sb.length() +
", capacity:" + sb.capacity());
buildSomeString();
System.out.println("length:" + sb.length() +
", capacity:" + sb.capacity());
buildSomeString(); // capacity shrinks to 16
System.out.println("length:" + sb.length() +
", capacity:" + sb.capacity());
}
static String buildSomeString() {
sb.setLength(0); // clear out old characters
System.out.println("after setLength length:" + sb.length() +
", capacity:" + sb.capacity());
sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
return sb.toString();
// return sb.substring(0, sb.length()); // problem goes away...
}
}
If you run this code you will see that after "buildSomeString()" is called the
second time, the capacity of the StringBuffer has been reduced to 16. This
problem only occurs if a String constructor has been passed a StringBuffer
object as a parameter (which causes the StringBuffer's "shared" flag to be set
to true) *AND* the StringBuffer's length is later set to zero. The coding error
is in the "StringBuffer.setLength()" method.
If you change the return statement in the "buildSomeString()" method to "return
sb.substring(0, sb.length());", the problem goes away.
When a programmer sets the capacity of a StringBuffer, he does so to increase
efficiency. The "setLength()" method sneakily undoes the programmer's good
intentions by setting the capacity back to the default of 16 characters, for no
good reason.
(Review ID: 135229)
======================================================================