+ 和 Stringbuilder 附加性能

Joh*_*ohn 2 java performance stringbuilder concatenation

我做了一个性能测试

    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());
Run Code Online (Sandbox Code Playgroud)

结果是

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
Run Code Online (Sandbox Code Playgroud)

相差13秒!!!

但我到处都看到“+”运算符更快的标语,因为从 java 1.6 开始它就得到了优化。怎么了?我哪里弄错了?

Eva*_*rke 5

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

String s = new StringBuilder().append(string1).append(string2).append(string3).toString();
String s = string1 + string2 + string3;
Run Code Online (Sandbox Code Playgroud)

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

    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();  
    }
Run Code Online (Sandbox Code Playgroud)

请注意,后者在每次循环迭代中分配一个新的 StringBuilder 并每次对结果调用 toString 。您可以通过查看“javac Test.java && javap -c Test”生成的字节码来验证这一点。根据经验,如果您的字符串连接可以写为一个表达式,则最好使用 + 运算符以提高可读性。

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