在循环中重用StringBuilder会更好吗?

我有一个关于使用StringBuilder的性能相关问题。 在一个很长的循环中,我操纵一个StringBuilder并将它传递给另一个方法,如下所示:

for (loop condition) {
    StringBuilder sb = new StringBuilder();
    sb.append("some string");
    . . .
    sb.append(anotherString);
    . . .
    passToMethod(sb.toString());
}

在每个循环周期实例化StringBuilder是一个很好的解决方案吗? 并且更好地调用删除,如下所示?

StringBuilder sb = new StringBuilder();
for (loop condition) {
    sb.delete(0, sb.length);
    sb.append("some string");
    . . .
    sb.append(anotherString);
    . . .
    passToMethod(sb.toString());
}

第二个是我的迷你基准测试中快25%左右。

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 );
    }
}

结果:

25265
17969

请注意,这是JRE 1.6.0_07。


根据Jon Skeet在编辑中的想法,这里是第2版。虽然结果相同。

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 );
    }
}

结果:

5016
7516

在编写可靠代码的哲学中,最好将您的StringBuilder放入循环中。 这样它就不会超出其预期的代码范围。

其次,在StringBuilder中最大的改进来自给它一个初始大小,以避免它在循环运行时变大

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

更快:

public class ScratchPad {

    private static String a;

    public static void main( String[] args ) throws Exception {
        long time = System.currentTimeMillis();
        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( String aString ) {
        a = aString;
    }
}

在编写可靠代码的哲学中,方法的内部工作应该从使用该方法的对象中隐藏起来。 因此,无论是在循环内还是在循环外重新声明StringBuilder,系统的角度都没有什么不同。 由于在循环之外声明它更快,并且不会使代码更加复杂,因此请重用该对象而不是重新实例化它。

即使代码更复杂,并且您肯定知道对象实例化是瓶颈,请对其进行评论。

三个运行这个答案:

$ java ScratchPad
1567
$ java ScratchPad
1569
$ java ScratchPad
1570

三个运行与其他答案:

$ java ScratchPad2
1663
2231
$ java ScratchPad2
1656
2233
$ java ScratchPad2
1658
2242

虽然不显着,但设置StringBuilder的初始缓冲区大小将会带来一点收益。

链接地址: http://www.djcxy.com/p/72357.html

上一篇: Is it better to reuse a StringBuilder in a loop?

下一篇: Clearing a string buffer/builder after loop