神话

用加号运算符连接两个字符串是万恶之源

-匿名Java开发人员

注意 :此处讨论的测试的源代码可以在Github上找到

从大学时代起,我就学会了使用+运算符将Java中的String连接视为致命的性能缺陷。 最近,在Backbase R&D上进行了一次内部审查,其中每当您使用plus运算符连接String时,由于在javac使用StringBuilder javac ,这种重复的口头禅就被当作神话了。 我准备证明这一点并验证不同环境下的现实。

考试

依靠编译器优化String串联意味着根据您采用的JDK供应商,情况可能会发生重大变化。 就我日常工作所需的平台支持而言,应考虑三个主要供应商:

  • Oracle JDK
  • IBM JDK
  • ECJ-仅适用于开发人员

此外,尽管我们正式支持Java 5至6,但我们也正在考虑为我们的产品提供Java 7支持,在这三个供应商的基础上增加了另外三层的间接。 为了 懒惰 为简单起见, ecj编译的字节码将使用单个JDK(即Oracle JDK7)运行。 我准备了安装了上述所有JDK的Virtualbox VM,然后开发了一些类来表示三种不同的串联方法,根据特定的测试用例,每种方法调用总计三至四个串联。 每个测试回合都运行测试类数千次,每个测试用例总共进行100回合。 相同的VM用于运行同一测试用例的所有回合,并跨不同的测试用例重新启动,所有这些都使Java运行时能够执行所有可能的优化,而不会以任何方式影响其他测试用例。 缺省选项用于启动所有JVM。 可以在基准运行程序脚本中找到更多详细信息。

编码

Github上提供了测试用例和测试套件的完整代码。 产生了以下不同的测试用例,以测量String串联的性能差异,加上直接使用StringBuilder

// String concat with plus
String result = 'const1' + base;
result = result + 'const2';
// String concat with a StringBuilder
new StringBuilder().append('const1').append(base).append('const2').append(append).toString();
}
//String concat with an initialized StringBuilder
new StringBuilder('const1').append(base).append('const2').append(append).toString();

一般的想法是在变量的常量String的开头和结尾都提供一个串联。 后两种情况(两者都显式使用StringBuilder之间的区别在于后者使用1-arg构造函数,该构造函数使用结果的初始部分初始化构建器。

结果

足够多的讨论,您可以在下面查看生成的图形,其中每个数据点对应一个测试回合(例如,同一测试类的1000次执行)。 随后将讨论结果以及更多细节。

讨论

甲骨文JKD5显然是输家,与其他甲骨文相比似乎处于B联赛。 但这实际上不是本练习的范围,因此我们暂时将其忽略。 也就是说,我在上图中观察到了另外两个有趣的地方。 首先是,使用加号运算符与使用显式StringBuilder通常确实存在很大的差异, 尤其是如果您使用的Oracle Java5的执行树时间比其他工作人员差的话。

第二个观察结果是,虽然对于大多数JDK来说,显式StringBuilder通常提供的速度是常规plus运算符的两倍,但IBM JDK6似乎不会遭受任何性能损失,它总是平均需要25ms才能完成任务。所有测试用例。 仔细查看生成的字节码会发现一些有趣的细节

字节码

注意:反编译类也可以在Github上使用。在所有可能的JDK中,即使存在加号, StringBuilders 始终用于实现String串联。 而且,在所有厂商和版本中,同一测试用例几乎没有任何区别 。 唯一的区别是ecj ,这是唯一巧妙地优化CatPlus测试用例以调用StringBuilder的1-arg构造函数而不是0-arg版本的方法。

比较生成的字节码可以揭示在不同场景下可能影响性能的因素:

  • 与plus串联时,只要发生串联,就会创建StringBuilder新实例 。 由于构造函数的无用调用,这很容易导致性能下降,并且由于丢弃实例而给垃圾收集器带来更多压力
  • 如果且仅当您在原始代码中以这种方式编写StringBuilder ,编译器才会照搬您,并且仅使用String的1-arg构造函数来初始化StringBuilder 。 这分别导致对CatSB和CatSB2的StringBuilder.append四个和三个调用。

结论

字节码分析为原始问题提供了最终答案。 您是否需要显式使用StringBuilder来提高性能? 上面的图清楚地表明,除非使用IBM JDK6运行时,否则在使用plus运算符时,您将损失50%的性能,尽管在显式StringBuilder时,它在候选对象上的表现会稍差一些。 同样,看到JIT优化如何影响整体性能也很有趣:例如,即使在两个显式StringBuilder测试用例之间存在不同的字节码,从长远来看,最终结果也绝对相同。


参考: Java StringBuilder神话从我们的JCG合作伙伴 Carlo Sciolla在Skuro博客中揭穿 。

翻译自: https://www.javacodegeeks.com/2013/03/java-stringbuilder-myth-debunked.html

Java StringBuilder神话被揭穿相关推荐

  1. Java StringBuilder

    Java StringBuilder class is mutable sequence of characters. StringBuilder Class can be comparable to ...

  2. java stringbuilder 清空问题

    java stringbuilder 清空问题 我也是碰到了这个问题才开始研究的,网上答案偏多,并且时间范围也比较大,各个版本的java 优化也不清楚,只能说我的java环境是1.7,测试给大家看. ...

  3. android stringbuilder 清空,java stringbuilder清空的方法

    java stringbuilder清空的三种方法 1.新生成一个,旧的由系统自动回收 2.delete 方法 builder1.delete(0, builder.length()); 3.Leng ...

  4. java stringbuilder 替换字符串_java中的经典问题StringBuilder替换String

    遇到一个面试题:在下面的例子中用"+"运算符连接字符串与用StringBuilder对象的append方法连接字符串哪个性能比较优异. 下图是给出的例子,例一,使用"+& ...

  5. java stringbuilder换行_初遇Java StringBuffer 和 StringBuilder 类利用 StringBuilder 给TextView实现换行处理...

    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类. 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够 ...

  6. Java StringBuilder getChars()方法与示例

    StringBuilder类的getChars()方法 (StringBuilder Class getChars() method) getChars() method is available i ...

  7. Java StringBuilder codePointAt()方法与示例

    StringBuilder类codePointAt()方法 (StringBuilder Class codePointAt() method) codePointAt() method is ava ...

  8. Java StringBuilder subSequence()方法与示例

    StringBuilder类subSequence()方法 (StringBuilder Class subSequence() method) subSequence() method is ava ...

  9. Java StringBuilder codePointCount()方法与示例

    StringBuilder类codePointCount()方法 (StringBuilder Class codePointCount() method) codePointCount() meth ...

最新文章

  1. ug二次开发环境可以用c语言吗,NX二次开发(1):开发环境配置
  2. pyqt 多线程使用
  3. C语言简洁代码:1006 换个格式输出整数 (15分)
  4. java 设置头错误信息,错误:在node.js中发送标头后无法设置标头
  5. jeecg 服务器 + linux + nginx 安装
  6. 查看http的并发请求数及其TCP连接状态
  7. js中this的理解
  8. 自定义添加的鼠标事件
  9. qscoj:喵哈哈村的卢西奥
  10. red hat linux 7.1 使用手册!,linux入门教材(Red Hat Linux 7.1)
  11. ubantu下谷歌浏览器安装包
  12. 游戏服务器开发都要学什么
  13. 信息差暴利副业项目,让你日入500+
  14. SiebelAdapter--具体干事的类,
  15. IDEA关联MySQL数据库库
  16. 新元宇宙奇科幻小说原创作品每周连载《地球人奇游天球记》第九回女神伴飞
  17. java 嵌入groovy_嵌入Groovy
  18. java.time.ZoneId类详解
  19. 一个知乎提问引发的(思考)[https://www.zhihu.com/question/263431508/answer/574084280]
  20. DJI Care 行业无忧悦享基础版

热门文章

  1. cmw500综合测试仪使用_山西优质三相直流电阻测试仪图片-南电合创
  2. think-in-java(17)容器深入研究
  3. 匿名内部类与Lambda表达式习题
  4. 跟踪React流–将Spring Cloud Sleuth与Boot 2结合使用
  5. jpa一级缓存和二级缓存_了解一级JPA缓存
  6. 清除java_如何在Java地毯下有效地清除问题
  7. 请使用复选框选择_使用可选是可选的
  8. java锁性能对比_提高Java的锁性能
  9. java字节码_好的,每个接触Java字节码的人
  10. 更好的默认NullPointerException消息是否会传入Java?