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 Stringconstructors 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.
 
    