Berin Loritsch a écrit : > > Friends, going through the source code looking for > places to optimize the critical path (i.e. the path > taken when no error or log message is performed), > I went through adding StringBuffers where there were > three or more strings to concatenate. > > I found an enigma. > > In several places, where the code was already using > a StringBuffer, I found code snippets like this: > > buffer.append("<" + prefix + ":" + name + "/>"); > > This gets expanded into the much more complex code as > follows: > > buffer.append( > new StringBuffer( > new StringBuffer( > new StringBuffer( > new StringBuffer("<").append(prefix).toString() > ).append(":").toString() > ).append(name).toString() > ).append("/>").toString() > ); > > That means four additional StringBuffers were created > behind the scenes. This is ludicrous when we are already > using StringBuffers--and wasteful of resources. > > Instead, please write the code to explicitly take advantage > of the StringBuffer when it is available: > > buffer.append("<").append(prefix).append(":").append(name).append("/>"); > > This is more respectful of the environment, and is much quicker > to execute on any JVM. > > Please, be mindful in the future.
Berin, Having once looked at the generated bytecode for string concatenation, I came to the conclusion that replacing "+" on Strings by append() on StringBuffers is really not worth it as far as performance is concerned, apart of course in the above case which involves concatenation in appends (and a strange compiler behaviour). Take the following example. The two methods do exactly the same thing, one with String concatenation, and the other one with StringBuffer.append(). package proto; public class TestSBuff { public void test1(int i, String msg) { System.out.println("The value " + "of i is " + i + " and the value of msg is '" + msg + "'"); } public void test2(int i, String msg) { System.out.println(new StringBuffer("The value ") .append("of i is ") .append(i) .append(" and the value of msg is '") .append(msg) .append("'") .toString()); } } Here's the resulting bytecode, output with javap -c : Compiled from TestSBuff.java public class proto.TestSBuff extends java.lang.Object { public proto.TestSBuff(); public void test1(int, java.lang.String); public void test2(int, java.lang.String); } Method proto.TestSBuff() 0 aload_0 1 invokespecial #1 <Method java.lang.Object()> 4 return Method void test1(int, java.lang.String) 0 getstatic #2 <Field java.io.PrintStream out> 3 new #3 <Class java.lang.StringBuffer> 6 dup 7 invokespecial #4 <Method java.lang.StringBuffer()> 10 ldc #5 <String "The value of i is "> 12 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 15 iload_1 16 invokevirtual #7 <Method java.lang.StringBuffer append(int)> 19 ldc #8 <String " and the value of msg is '"> 21 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 24 aload_2 25 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 28 ldc #9 <String "'"> 30 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 33 invokevirtual #10 <Method java.lang.String toString()> 36 invokevirtual #11 <Method void println(java.lang.String)> 39 return Method void test2(int, java.lang.String) 0 getstatic #2 <Field java.io.PrintStream out> 3 new #3 <Class java.lang.StringBuffer> 6 dup 7 ldc #12 <String "The value "> 9 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)> 12 ldc #14 <String "of i is "> 14 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 17 iload_1 18 invokevirtual #7 <Method java.lang.StringBuffer append(int)> 21 ldc #8 <String " and the value of msg is '"> 23 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 26 aload_2 27 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 30 ldc #9 <String "'"> 32 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)> 35 invokevirtual #10 <Method java.lang.String toString()> 38 invokevirtual #11 <Method void println(java.lang.String)> 41 return Two things are shown above : * String concatenation is translated to StringBuffer.append() instructions. The only difference with direct StringBuffer code is that the default no-arg StringBuffer() constructor is called and the first string is appended like others. I'm not sure this small benefit justifies the decreased code readability (and the increased keyboard typing ;) * Constant String concatenation (like "The value " + "of i is ") isn't translated to individual StringBuffer.append(), but to a single String constant ("The value of i is "). In that case, performance is better with String concatenation. This means some of the changes you made on code where constant strings are concatenated to allow line-splitting (see for example WildcardURIMatcherFactory) are in fact slowing down the code ! The conclusion is that StringBuffer is only worth it when the concatenation occurs in several statements, or iteratively such as in a "for" loop. Otherwhise, single-statement String concatenations can be considered equivalent to their StringBuffer translation, but produce less readable code. Sylvain. -- Sylvain Wallez Anyware Technologies - http://www.anyware-tech.com --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]