+和Stringbuilder追加性能

时间:2017-06-30 04:05:39

标签: java performance concatenation stringbuilder

我做了一次性能测试

    String test="";
    Date st = new Date();
    logger.info("start "+(new Date()).toString());
    for(int i = 0;i<100000;i++) {
        test += "test";  
    }
    logger.info("end "+(new Date()).toString());

    test="";
    StringBuilder sb = new StringBuilder(test);
    logger.info("start Sb "+(new Date()).toString());
    for(int i = 0;i<100000;i++) {
        sb.append("test");  
    }
    test = sb.toString();
    logger.info("end sb "+(new Date()).toString());

,结果是

start Fri Jun 30 10:34:42 KRAT 2017
end Fri Jun 30 10:34:55 KRAT 2017
start Sb Fri Jun 30 10:34:55 KRAT 2017
end sb Fri Jun 30 10:34:55 KRAT 2017

差异是13秒!!!

但在任何地方我都读到口号“+”运算符更快,因为自java 1.6以来它已经过优化。怎么了?哪里弄错了?

2 个答案:

答案 0 :(得分:2)

+通过分配StringBuilder并调用append来实现。以下代码行是等效的:

String s = new StringBuilder().append(string1).append(string2).append(string3).toString();
String s = string1 + string2 + string3;

不幸的是,编译器并不擅长在循环中识别String连接链,因此以下代码段也是等效的。

    String test="";
    for(int i = 0;i<100000;i++) {
        test += "test";  
    }

    String test="";
    for(int i = 0;i<100000;i++) {
        test = new StringBuilder().append(test).append("test").toString();  
    }

请注意,后者在每次循环迭代中都会分配一个新的StringBuilder,并且每次都会对结果调用toString。您可以通过查看&#39; javac Test.java&amp;&amp ;;生成的字节码来验证这一点。 javap -c测试&#39;。根据经验,如果您的字符串连接可以写成一个表达式,那么首选+运算符以便于阅读。

关于编写这些基准的附注: 您测试每个替代方案的顺序会影响其性能。您应该为每个版本编写两个单独的主要方法,以便您的测试是独立的。此外,您使用名为test的变量进行了大量工作,但未在任何地方使用它。编译器可以自由地优化你的第一个for循环,因为之后会立即重置test的值。

答案 1 :(得分:0)

&#34; +&#34;普通字符串上的运算符比&#34;追加&#34;慢得多。 StringBuilder上的操作。渐渐地,&#34; +&#34;普通字符串上的运算符具有O(n*m)时间复杂度,其中n是旧字符串的大小,m是要追加的字符串的大小,而&#34;追加&#34; StringBuilder上的操作只有O(m)复杂度。

<强>阐释:

字符串是不可变的。因此,每次执行test + "test"时,都会创建一个新字符串,并将测试字符串的所有字符附加到新字符串,然后是&#34; test&#34;的所有字符。因此,附加的总字符数为test.length() + "test".length()

StringBuilder是可变的。因此,每次执行sb.append("test)时,只会出现&#34; test&#34;被附加到现有的&#34; sb&#34;。因此,附加的总字符数为"test".length()