views:

95

answers:

6

All,

I was wondering if clearing a StringBuffer contents using the setLength(0) would make sense. i.e. Is it better to do :

while (<some condition>)
{
    stringBufferVariable = new StringBuffer(128);
    stringBufferVariable.append(<something>)
                        .append(<more>)
                        ... ;
    Append stringBufferVariable.toString() to a file;
    stringBufferVariable.setLength(0);
}

My questions:
1 > Will this still have better performance than having a String object to append the contents?

I am not really sure how reinitializing the StringBuffer variable would affect the performance and hence the question.

Please pour in your comments

[edit]: Removed the 2nd question about comparing to StringBuilder since I have understood there nothing more to look into based on responses.

A: 

1 > Will this still have better performance than having a String object to append the contents?

Yes, concatenating Strings is slow since you keep creating new String Objects.

2 > If using StringBuilder would perform better than StringBuffer here, than why?

Have you read the API description for StringBuilder and/or StringBuffer? This issued is addressed there.

I am not really sure how reinitializing the StringBuffer variable would affect the performance and hence the question.

Well create a test program. Create a test that creates a new StringBuffer/Builder every time. Then rerun the test and just reset the characters to 0 and then compare the times.

camickr
Yes I did. StringBuilder is not sync'ed and hence performs better than StringBuffer. Just wanted to be sure if there is no other factor that might affect the performance.
darkie15
+1  A: 

For question 2, StringBuilder will perform better than StringBuffer. StringBuffer is thread safe, meaning methods are synchronized. String Builder is not synchronized. So if the code you have is going to be run by ONE thread, then StringBuilder is going to have better performance since it does not have the overhead of doing synchronization.

As camickr suggest, please check out the API for StringBuffer and StringBuilder for more information.

Also you may be interested in this article: The Sad Tragedy of Micro-Optimization Theater

Alvin
+4  A: 

Better than concatenating strings?

If you're asking whether

stringBufferVariable.append("something")
                    .append("more");
...

will perform better than concatenating with +, then yes, usually. That's the whole reason these classes exist. Object creation is expensive compared to updating the values in a char array.

It appears most if not all compilers now convert string concatenation into using StringBuilder in simple cases such as str = "something" + "more" + "...";. The only performance difference I can then see is that the compiler won't have the advantage of setting the initial size. Benchmarks would tell you whether the difference is enough to matter. Using + would make for more readable code though.

From what I've read, the compiler apparently can't optimize concatenation done in a loop when it's something like

String str = "";
for (int i = 0; i < 10000; i++) {
    str = str + i + ",";
}

so in those cases you would still want to explicitly use StringBuilder.

StringBuilder vs StringBuffer

StringBuilder is not thread-safe while StringBuffer is, but they are otherwise the same. The synchronization performed in StringBuffer makes it slower, so StringBuilder is faster and should be used unless you need the synchronization.

Should you use setLength?

The way your example is currently written I don't think the call to setLength gets you anything, since you're creating a new StringBuffer on each pass through the loop. What you should really do is

StringBuilder sb = new StringBuilder(128);
while (<some condition>) {
    sb.append(<something>)
      .append(<more>)
      ... ;
    // Append stringBufferVariable.toString() to a file;
    sb.setLength(0);
}

This avoids unnecessary object creation and setLength will only be updating an internal int variable in this case.

bemace
Haven't marked down but the first part is wrong, the compiler will use a StringBuilder there.
Tom
@Tom - thanks, I wasn't aware of that optimization. Did some research and improved my answer.
bemace
A: 

Perhaps I am misunderstanding something in your question... why are you setting the length to 0 at the bottom if you are just creating a new one at the start of each iteration?

Assuming the variable is a local variable to the method or that it will not be using by multiple threads if it is declared outside of a method (if it is outside of a method your code probably has issues though) then make it a StringBuilder.

If you declare the StringBuilder outside of the loop then you don't need to make a new one each time you enter the loop but you would want to set the length to 0 at the end of the loop.

If you declare the StringBuilder inside of the loop then you don't need to set the length to 0 at the end of the loop.

It is likely that declaring it outside of the loop and setting the length to 0 will be faster, but I would measure both and if there isn't a large difference declare the variable inside the loop. It is good practice to limit the scope of variables.

TofuBeer
+2  A: 

I'm just focusing on this part of the question. (The other parts have been asked and answered many times before on SO.)

I was wondering if clearing a StringBuffer contents using the setLength(0) would make sense.

It depends on the Java class libraries you are using. In some older Sun releases of Java, the StringBuffer.toString() was implemented on the assumption that a call to sb.toString() is the last thing that is done with the buffer. The StringBuffer's original backing array becomes part of the String returned by toString(). A subsequent attempt to use the StringBuffer resulted a new backing array being created and initialized by copying the String contents. Thus, reusing a StringBuffer as your code tries to do would actually make the application slower.

With Java 1.5 and later, a better way to code this is as follows:

    bufferedWriter.append(stringBufferVariable);
    stringBufferVariable.setLength(0);

This should copy the characters directly from the StringBuilder into the file buffer without any need to create a temporary String. Providing that the StringBuffer declaration is outside the loop, the setLength(0) then allows you to reuse the buffer.

Finally, you should only be worrying about all of this if you have evidence that this part of the code is (or is likely to be) a bottleneck. "Premature optimization is the root of all evil" blah, blah.

Stephen C
**Note** : the part about `toString` is only true for versions prior of Java 1.5! For Java 1.6 and 1.5, the javadoc for StringBuilder and StringBuffer states: "...A new String object is allocated... This String is then returned. Subsequent changes to this sequence do not affect the contents of the String."
Carlos Heuberger
@Carlos - The difference before / after Java 1.5 was in the way that toString() was implemented, not in the way that it behaved.
Stephen C
A: 

yup! setLength(0) is a great idea! that's what its for. anything quicker would be to discard the stringBuffer & make a new one. its faster, can't say anything about it being memory efficient :)

ksm
How would creating a new buffer be faster than reusing the existing one?
bemace