A DESCRIPTION OF THE REQUEST :
A typical use of StringBuilder(int) is to preallocate a buffer in one time, specifying a predicted length for the internal char[] backing store, and we use it instead of multiple append(...) operations that causeexcessive reallocations. The problem is that there's still no constructor for StringBuilder or its parent AbstractStringBuilder where we can specify BOTH the initial capacity AND the effective length (in addition we cannot specify early the character to use when prefilling the array).
So we perform code such as:
int length=(/*expression computing length*/);
Stringbuilder result = newStringBuilder(length);
result.setLength(length);
then we are sure that no reallocation will ever occur when filling the content with setCharAt(...). We need to use StringBuilder because this is the only supported class that allow us to finally create a String object without additional copies or reallocations.
There's still one problem: the setLength(int) method takes too much time trying to fill the internal backing store with null characters; it uses a loop to fill the positions, but in fact it is not necessary, given that the positions are already filled by null characters when the internal backing store is already preallocated, or the capacity has already been expanded.
JUSTIFICATION :
For some applications that handle large volume of texts (such as transcoders, or Base64/Hex converters) removing the unnecessary null-filling loop gives extra throughput...
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would like to replace the existing code at end of the AbstractSringBuilder.setLength(int) method by a simple only with the "count = newLength;" statement.
The suggested fix is to avoid the code that fills the new increased length:
package java.lang;
public class AbstractStringBuilder {
//...
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
if (newLength > value.length)
// expandCapacity already fills the extra length with nulls...
// per definition of Javas's "new char[]" allocator...
expandCapacity(newLength);
count = newLength;
}
}
//...
}
ACTUAL -
In other words, I suggest to remove the extra test and loop at end of this method :
if (count < newLength) {
for (; count < newLength; count++)
value[count] = '\0';
} else {
count = newLength;
}
only by:
count = new Length;
because the test and loop is COMPLETELY unnecessary. Look at how "expandCapacity(int newSize)" works, it uses :
- an allocation with "new char[]" internally, prefilling the whole length with nulls, per definition of the operation,
- Arrays.copyOf(...) that will perform the copy of the previous characters from the old buffer
---------- BEGIN SOURCE ----------
Typical code where this change improves things:
int size = 16*1024*1024;
StringBuilder result = new StringBuilder(size);
result.setLength(size);
setLength() will perform an unnecessary loop for filling the new length with nulls.
But any application method that is used very frequently to work with moderate string builders or string buffers with known final length is experimenting this slower execution path. (I detected this loop when profiling my code)
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
This is a RFE only for performance (nothing changed in the SDK API or semantic or results of the method)
A typical use of StringBuilder(int) is to preallocate a buffer in one time, specifying a predicted length for the internal char[] backing store, and we use it instead of multiple append(...) operations that causeexcessive reallocations. The problem is that there's still no constructor for StringBuilder or its parent AbstractStringBuilder where we can specify BOTH the initial capacity AND the effective length (in addition we cannot specify early the character to use when prefilling the array).
So we perform code such as:
int length=(/*expression computing length*/);
Stringbuilder result = newStringBuilder(length);
result.setLength(length);
then we are sure that no reallocation will ever occur when filling the content with setCharAt(...). We need to use StringBuilder because this is the only supported class that allow us to finally create a String object without additional copies or reallocations.
There's still one problem: the setLength(int) method takes too much time trying to fill the internal backing store with null characters; it uses a loop to fill the positions, but in fact it is not necessary, given that the positions are already filled by null characters when the internal backing store is already preallocated, or the capacity has already been expanded.
JUSTIFICATION :
For some applications that handle large volume of texts (such as transcoders, or Base64/Hex converters) removing the unnecessary null-filling loop gives extra throughput...
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would like to replace the existing code at end of the AbstractSringBuilder.setLength(int) method by a simple only with the "count = newLength;" statement.
The suggested fix is to avoid the code that fills the new increased length:
package java.lang;
public class AbstractStringBuilder {
//...
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
if (newLength > value.length)
// expandCapacity already fills the extra length with nulls...
// per definition of Javas's "new char[]" allocator...
expandCapacity(newLength);
count = newLength;
}
}
//...
}
ACTUAL -
In other words, I suggest to remove the extra test and loop at end of this method :
if (count < newLength) {
for (; count < newLength; count++)
value[count] = '\0';
} else {
count = newLength;
}
only by:
count = new Length;
because the test and loop is COMPLETELY unnecessary. Look at how "expandCapacity(int newSize)" works, it uses :
- an allocation with "new char[]" internally, prefilling the whole length with nulls, per definition of the operation,
- Arrays.copyOf(...) that will perform the copy of the previous characters from the old buffer
---------- BEGIN SOURCE ----------
Typical code where this change improves things:
int size = 16*1024*1024;
StringBuilder result = new StringBuilder(size);
result.setLength(size);
setLength() will perform an unnecessary loop for filling the new length with nulls.
But any application method that is used very frequently to work with moderate string builders or string buffers with known final length is experimenting this slower execution path. (I detected this loop when profiling my code)
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
This is a RFE only for performance (nothing changed in the SDK API or semantic or results of the method)