You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Berin Loritsch <bl...@apache.org> on 2001/10/25 21:02:19 UTC

StringBuffers and String Concatenation

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.

---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org


Re: StringBuffers and String Concatenation

Posted by Michael McKibben <mm...@ncube.com>.
What really stinks about using a StringBuffer (and therefore the +
operator) is that append's are synchronized!! To really see an impact on
performance, use a custom string buffer class that is not thread safe and
use StringBuffers only where thead safety is required.

Regards,

--mike

On Fri, 26 Oct 2001, Sylvain Wallez wrote:

>
> 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: cocoon-dev-unsubscribe@xml.apache.org
> For additional commands, email: cocoon-dev-help@xml.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org


Re: StringBuffers and String Concatenation

Posted by Sylvain Wallez <sy...@anyware-tech.com>.
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: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org