Java StringBuilder神话被揭穿
神话
用加号运算符连接两个字符串是万恶之源
-匿名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神话被揭穿相关推荐
- Java StringBuilder
Java StringBuilder class is mutable sequence of characters. StringBuilder Class can be comparable to ...
- java stringbuilder 清空问题
java stringbuilder 清空问题 我也是碰到了这个问题才开始研究的,网上答案偏多,并且时间范围也比较大,各个版本的java 优化也不清楚,只能说我的java环境是1.7,测试给大家看. ...
- android stringbuilder 清空,java stringbuilder清空的方法
java stringbuilder清空的三种方法 1.新生成一个,旧的由系统自动回收 2.delete 方法 builder1.delete(0, builder.length()); 3.Leng ...
- java stringbuilder 替换字符串_java中的经典问题StringBuilder替换String
遇到一个面试题:在下面的例子中用"+"运算符连接字符串与用StringBuilder对象的append方法连接字符串哪个性能比较优异. 下图是给出的例子,例一,使用"+& ...
- java stringbuilder换行_初遇Java StringBuffer 和 StringBuilder 类利用 StringBuilder 给TextView实现换行处理...
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类. 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够 ...
- Java StringBuilder getChars()方法与示例
StringBuilder类的getChars()方法 (StringBuilder Class getChars() method) getChars() method is available i ...
- Java StringBuilder codePointAt()方法与示例
StringBuilder类codePointAt()方法 (StringBuilder Class codePointAt() method) codePointAt() method is ava ...
- Java StringBuilder subSequence()方法与示例
StringBuilder类subSequence()方法 (StringBuilder Class subSequence() method) subSequence() method is ava ...
- Java StringBuilder codePointCount()方法与示例
StringBuilder类codePointCount()方法 (StringBuilder Class codePointCount() method) codePointCount() meth ...
最新文章
- ug二次开发环境可以用c语言吗,NX二次开发(1):开发环境配置
- pyqt 多线程使用
- C语言简洁代码:1006 换个格式输出整数 (15分)
- java 设置头错误信息,错误:在node.js中发送标头后无法设置标头
- jeecg 服务器 + linux + nginx 安装
- 查看http的并发请求数及其TCP连接状态
- js中this的理解
- 自定义添加的鼠标事件
- qscoj:喵哈哈村的卢西奥
- red hat linux 7.1 使用手册!,linux入门教材(Red Hat Linux 7.1)
- ubantu下谷歌浏览器安装包
- 游戏服务器开发都要学什么
- 信息差暴利副业项目,让你日入500+
- SiebelAdapter--具体干事的类,
- IDEA关联MySQL数据库库
- 新元宇宙奇科幻小说原创作品每周连载《地球人奇游天球记》第九回女神伴飞
- java 嵌入groovy_嵌入Groovy
- java.time.ZoneId类详解
- 一个知乎提问引发的(思考)[https://www.zhihu.com/question/263431508/answer/574084280]
- DJI Care 行业无忧悦享基础版
热门文章
- cmw500综合测试仪使用_山西优质三相直流电阻测试仪图片-南电合创
- think-in-java(17)容器深入研究
- 匿名内部类与Lambda表达式习题
- 跟踪React流–将Spring Cloud Sleuth与Boot 2结合使用
- jpa一级缓存和二级缓存_了解一级JPA缓存
- 清除java_如何在Java地毯下有效地清除问题
- 请使用复选框选择_使用可选是可选的
- java锁性能对比_提高Java的锁性能
- java字节码_好的,每个接触Java字节码的人
- 更好的默认NullPointerException消息是否会传入Java?