HomeBlogAboutTools

On Java String Concatenation

uncategorized

Most Java programmers know to use a StringBuffer (or a JDK 1.5 StringBuilder) when concatenating Strings in Java, but it occurred to me that the compiler might be able to optimize some of these calls.

For instance, look at the following code: “

    StringBuffer buf = new StringBuffer();
    buf.append("one" + "two");

There is an obvious optimization there: combine “one” and “two” into a single String before appending them to the StringBuffer.

Sure enough: “

   L0 (0)
    NEW StringBuffer
    DUP
    INVOKESPECIAL StringBuffer.() : void
    ASTORE 0: buf
   L1 (5)
    ALOAD 0: buf
    LDC "onetwo"
    INVOKEVIRTUAL StringBuffer.append(String) : StringBuffer
    POP

Note the LDC "onetwo" line - the compiler has combined the two strings in the bytecode itself.

However, the following code: “

    String one = "str1";
    StringBuffer buf = new StringBuffer();
    buf.append(one + "two");

gives: L0 (0) LDC "str1" ASTORE 0: one L1 (3) NEW StringBuffer DUP INVOKESPECIAL StringBuffer.() : void ASTORE 1: buf L2 (8) ALOAD 1: buf NEW StringBuffer DUP ALOAD 0: one INVOKESTATIC String.valueOf(Object) : String INVOKESPECIAL StringBuffer.(String) : void LDC "two" INVOKEVIRTUAL StringBuffer.append(String) : StringBuffer INVOKEVIRTUAL StringBuffer.toString() : String INVOKEVIRTUAL StringBuffer.append(String) : StringBuffer POP Hmm - that isn’t good at all. The code one + "two" causes the compiler to create a new StringBuffer, concatenate the two Strings, call toString on the temporary StringBuffer and append that to the original StringBuffer. Looks like that should be written: String one = "str1"; StringBuffer buf = new StringBuffer(); buf.append(one); buf.append("two"); which gives: L0 (0) LDC "str1" ASTORE 0: one L1 (3) NEW StringBuffer DUP INVOKESPECIAL StringBuffer.() : void ASTORE 1: buf L2 (8) ALOAD 1: buf ALOAD 0: one INVOKEVIRTUAL StringBuffer.append(String) : StringBuffer POP L3 (13) ALOAD 1: buf LDC "two" INVOKEVIRTUAL StringBuffer.append(String) : StringBuffer POP Much better!

There is one final (pun intended) change that I found interesting: “

    final String one = "str1";
    StringBuffer buf = new StringBuffer();
    buf.append(one + "two");

gives: L0 (0) LDC "str1" ASTORE 0: one L1 (3) NEW StringBuffer DUP INVOKESPECIAL StringBuffer.() : void ASTORE 1: buf L2 (8) ALOAD 1: buf LDC "str1two" INVOKEVIRTUAL StringBuffer.append(String) : StringBuffer POP Nice!

Obviously most of this is pretty logical and well known by most Java programmers. I found it interesting to see exactly what optimizations the complier (as opposed to the JVM) is doing though. (Note that these experiments were done using the Eclipse 3.0 JDK 1.4 complier. Other compiler optimizations may vary)