Note: This question is about Java >= 9 which introduced "compact strings"
Let's say I am appending an unknown number of strings (or chars) to a StringBuilder
and at some point determine that I am appending the last string.
How can this be done efficiently?
Background
If the capacity of the string builder is not large enough it will always increase it to max(oldCap + str.lenght(), oldCap * 2 + 2)
. So if you are unlucky and the capacity is not enough for the last string, it will unnecessarily double the capcity, e.g.:
StringBuilder sb = new StringBuilder(4000);
sb.append("aaa..."); // 4000 * "a"
// Last string:
sb.append("b"); // Unnecessarily increases capacity from 4000 to 8002
return sb.toString();
StringBuilder
offers the methods capacity()
, length()
and getChars(...)
, however manually creating a char[]
and then creating a string will be inefficient because:
- Due to "compact strings" the string builder has to convert its bytes to chars
- When calling one of the
String
constructors the chars have to be compacted to bytes again
Another option would be to check capacity()
and if necessary create a new StringBuilder(sb.length() + str.length())
, then append sb
and str
:
StringBuilder sb = new StringBuilder(4000);
sb.append("aaa..."); // 4000 * "a"
String str = "b";
if (sb.capacity() - sb.length() < str.length()) {
return new StringBuilder(sb.length() + str.length())
.append(sb)
.append(str)
.toString();
}
else {
return sb.append(str).toString();
}
The only disadvantage is that if the existing string builder or the new string is non-Latin 1 (2 bytes per char), the newly created string builder has to be "inflated" from 1 byte per char (Latin 1) to 2 bytes per char.