Is it better to reuse a StringBuilder in a loop? Is it better to reuse a StringBuilder in a loop? java java

Is it better to reuse a StringBuilder in a loop?


The second one is about 25% faster in my mini-benchmark.

public class ScratchPad {    static String a;    public static void main( String[] args ) throws Exception {        long time = System.currentTimeMillis();        for( int i = 0; i < 10000000; i++ ) {            StringBuilder sb = new StringBuilder();            sb.append( "someString" );            sb.append( "someString2"+i );            sb.append( "someStrin4g"+i );            sb.append( "someStr5ing"+i );            sb.append( "someSt7ring"+i );            a = sb.toString();        }        System.out.println( System.currentTimeMillis()-time );        time = System.currentTimeMillis();        StringBuilder sb = new StringBuilder();        for( int i = 0; i < 10000000; i++ ) {            sb.delete( 0, sb.length() );            sb.append( "someString" );            sb.append( "someString2"+i );            sb.append( "someStrin4g"+i );            sb.append( "someStr5ing"+i );            sb.append( "someSt7ring"+i );            a = sb.toString();        }        System.out.println( System.currentTimeMillis()-time );    }}

Results:

2526517969

Note that this is with JRE 1.6.0_07.


Based on Jon Skeet's ideas in the edit, here's version 2. Same results though.

public class ScratchPad {    static String a;    public static void main( String[] args ) throws Exception {        long time = System.currentTimeMillis();        StringBuilder sb = new StringBuilder();        for( int i = 0; i < 10000000; i++ ) {            sb.delete( 0, sb.length() );            sb.append( "someString" );            sb.append( "someString2" );            sb.append( "someStrin4g" );            sb.append( "someStr5ing" );            sb.append( "someSt7ring" );            a = sb.toString();        }        System.out.println( System.currentTimeMillis()-time );        time = System.currentTimeMillis();        for( int i = 0; i < 10000000; i++ ) {            StringBuilder sb2 = new StringBuilder();            sb2.append( "someString" );            sb2.append( "someString2" );            sb2.append( "someStrin4g" );            sb2.append( "someStr5ing" );            sb2.append( "someSt7ring" );            a = sb2.toString();        }        System.out.println( System.currentTimeMillis()-time );    }}

Results:

50167516


Faster still:

public class ScratchPad {    private static String a;    public static void main( String[] args ) throws Exception {        final long time = System.currentTimeMillis();        // Pre-allocate enough space to store all appended strings.        // StringBuilder, ultimately, uses an array of characters.        final StringBuilder sb = new StringBuilder( 128 );        for( int i = 0; i < 10000000; i++ ) {            // Resetting the string is faster than creating a new object.            // Since this is a critical loop, every instruction counts.            sb.setLength( 0 );            sb.append( "someString" );            sb.append( "someString2" );            sb.append( "someStrin4g" );            sb.append( "someStr5ing" );            sb.append( "someSt7ring" );            setA( sb.toString() );        }        System.out.println( System.currentTimeMillis() - time );    }    private static void setA( final String aString ) {        a = aString;    }}

In the philosophy of writing solid code, the inner workings of the method are hidden from the client objects. Thus it makes no difference from the system's perspective whether you re-declare the StringBuilder within the loop or outside of the loop. Since declaring it outside of the loop is faster, and it does not make the code significantly more complicated, reuse the object.

Even if it was much more complicated, and you knew for certain that object instantiation was the bottleneck, comment it.

Three runs with this answer:

$ java ScratchPad1567$ java ScratchPad1569$ java ScratchPad1570

Three runs with the other answer:

$ java ScratchPad216632231$ java ScratchPad216562233$ java ScratchPad216582242

Although not significant, setting the StringBuilder's initial buffer size, to prevent memory re-allocations, will give a small performance gain.


In the philosophy of writing solid code its always better to put your StringBuilder inside your loop. This way it doesnt go outside the code its intended for.

Secondly the biggest improvment in StringBuilder comes from giving it an initial size to avoid it growing bigger while the loop runs

for (loop condition) {  StringBuilder sb = new StringBuilder(4096);}