Best practices
I have a few questions about best practices when using Strings and StringBuffers.
Question 1: for concatenation StringBuffer or StringBuilder is the best option. How about search and replace? Does the same explanation apply here (use StringBuilder to avoid spawning too much objects) or does the String class have a faster way of searching its contents?
Question 2: for deleting characters from a sequence which one is faster?
StringBuilder builder =new StringBuilder("Sometext");
builder.delete(2,3);
or
String text ="SomeText";
text = text.substring(0,2) + text.substring(3);
Question 3: is there a performance difference between a.contains('*')
and a.indexOf('*') != -1
?
Regards,
Peter
# 1
> Question 1:
Depends on how you want to do it. String.replaceAll can be efficient.
> Question 2:
It will be about the same.
> Question 3:
Contains is implemented as:
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
Kaj
# 2
> Question 1: for concatenation StringBuffer or
> StringBuilder is the best option.
Do you need a synchronized or non-synchronized container?
> How about search and replace?
See above.
> Does the same explanation apply here
> (use StringBuilder to avoid spawning too much
> objects) or does the String class have a faster way
> of searching its contents?
Both are likely to iterate over a char array, so I wouldn't expect much of a difference.
> Question 2: for deleting characters from a sequence
> which one is faster?
I'd assume the latter, because not much is created or modified, you just get a view of the same char[] that backs "text". But that might as well depend on the JVM implementation. Plus, I'm not sure what delete() does to a StringBuffer/-Builder.
You could run a performance test, you know?
> Question 3: is there a performance difference between
Again, run a test.
# 3
> > Question 1: for concatenation StringBuffer or
> > StringBuilder is the best option.
>
> Do you need a synchronized or non-synchronized
> container?
That was just the introductory part that said that I knew I should use either StringBuffer or StringBuilder... The question started after that, but thanks!
I'll run a few tests.
# 4
For number 2, StringBuilder.delete does a simple index check to verify valid values, then does a System.arraycopy() and returns the resulting StringBuilder without creating a new instance. The String version creates a new String for each call to subString, and then creates another new String object for the concatentation. I would therefor assume that the StringBuilder version is much faster, but I doubt you would notice unless you are doing a lot of string manipulation in a loop.
Plus, as has been pointed out, StringBuilder is not thread-safe.
~Tim
# 5
> For number 2, StringBuilder.delete does a simple
> index check to verify valid values, then does a
> System.arraycopy() and returns the resulting
> StringBuilder without creating a new instance.
Which you still have to call toString on, and that will create a new String, and a new character array (if you are using JDK 1.5)
> The
> String version creates a new String for each call to
> subString,
But those two new strings are views into the original string so no new character arrays are created at that time.
> and then creates another new String object
> for the concatentation.
The compiler generates code which uses a StringBuilder/StringBuffer for the concatenation.
> I would therefor assume that
> the StringBuilder version is much faster,
See above. The difference is actually quite small.
Kaj
# 6
To provide a little more context on this one. I am writing a singlethreaded application that monitors log files for a mobile phone operator. It processes a lot of data and has to be quite performant. I compared the delete and use of 2 substrings. It's quite basic, and it shows a performance advantage for StringBuilder.
public static void main(String[] args)
{
Calendar startString = new GregorianCalendar();
for (int i = 0; i < 10000000; ++i) {
String test = "aaaaaaa";
test = test.substring(0,2) + test.substring(3);
}
Calendar endString = new GregorianCalendar();
Calendar startBuilder = new GregorianCalendar();
for (int i = 0; i< 10000000; ++i) {
StringBuilder builder = new StringBuilder("aaaaaaa");
builder.delete(2,3);
String test = builder.toString();
}
Calendar endBuilder = new GregorianCalendar();
Calendar startBuffer = new GregorianCalendar();
for (int i = 0; i< 10000000; ++i) {
StringBuffer buffer = new StringBuffer("aaaaaaa");
buffer.delete(2,3);
String test = buffer.toString();
}
Calendar endBuffer = new GregorianCalendar();
System.out.println(endString.getTimeInMillis() - startString.getTimeInMillis());
System.out.println(endBuffer.getTimeInMillis() - startBuffer.getTimeInMillis());
System.out.println(endBuilder.getTimeInMillis() - startBuilder.getTimeInMillis());
}
For 100000 iterations String and StringBuffer took 63 ms, StringBuilder took 31 ms.
For 10000000 iterations String took 4140ms, StringBuffer 5250 and the StringBuilder took 3063ms.
I guess overhead for the synchronization in StringBuffer costs more than creating a couple of extra String instances...
