deleteCharAt or setLength, which way is better to remove last char from a StringBuilder/StringBuffer

StackOverflow https://stackoverflow.com/questions/21645559

Question

In many cases, we need to delete the last char of a StringBuilder/StringBuffer. For example, given a int[]{1,2,3}, to implement a String toString(int[] a) method, contacting each elements with a comma separator. The output should be 1,2,3, no tailing comma.

We can easily write a loop:

int[] nums = new int[]{1,2,3,4,5};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < nums.length; i++) {
    sb.append(nums[i]);
    sb.append(",");
}
//here we need to remove the tailing ','

but always we need to remove the tailing ','. There are two ways to implement it:

sb.deleteCharAt(sb.length() - 1);

and

sb.setLength(sb.length() - 1);

Which one is recommended? Why?

NOTE: I know what does Arrays.toString do. That's just an example to describe my question, maybe not quite proper. This is not a discussion about strings concatenation but the best practices of StringBuffer/StringBuilder.

Was it helpful?

Solution

Actually, there is very little in it and is probably dependent on hardware and other factors.

The setLength() method simply alters the count and overwrites the unwanted value in the array with a zero byte.

The deleteCharAt() performs an array copy internally, before altering the count. That sounds dramatic, but the array being copied is actually zero-length because you're removing the last character.

I would recommend going for setLength() as it is shorter to type and I think makes it clearer what you are doing. If performance is an issue and, on measuring, you find this is the bottleneck for you, then perhaps you could consider a different algorithm that doesn't require changing the size (as per JB Nizet's answer).

OTHER TIPS

How you do it properly is to conditionally prepend the comma:

for (int i = 0; i < nums.length; i++) {
    if (i > 0)
        sb.append(',');
    sb.append(nums[i]);
}

Then you don't need to worry about removing the last character, because it's already correct.

I wouldn't do it like this. Instead, I would only add a trailing comma if the element is not the last element of the array. Or I would use Guava's Joiner (or Apache-commons StringUtils), which makes it much clearer:

String s = Joiner.on(',').join(nums);

NB: I just noticed that Guava's Joiner doesn't deal with primitive arrays. You should get the idea from the above anyway.

If you need even greater speed, your use case might allow you to just keep your own variable

int activelength;

Then you can just do this operation with

activelength--;

This would be faster than

sb.setLength(sb.length() - 1);

which takes extra time clearing out the byte or word for safety.

Of course, the rest of your context will determine if this is a win for you or not, because other operations you may be needing, such as growing the StringBuilder, would take some extra logic to detect and invoke.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top