Java编译器不';t自动优化字符串连接?

Java编译器不';t自动优化字符串连接?,java,performance,optimization,jsoup,stringbuilder,Java,Performance,Optimization,Jsoup,Stringbuilder,以下代码连接容器中所有元素的文本els: for (Element el : els) entireText += el.text(); 在一个包含约64个元素的容器上,每个元素包含约1KB(整个文本的总容量约为64KB),在典型的低端Android手机上,这个简单的循环大约需要8秒钟 这种缓慢的性能有点让我吃惊,因为我觉得Java编译器用新的StringBuilder(A).append(B).append(C).toString()替换了A+B+C这样的表达式 不是

以下代码连接容器中所有元素的文本
els

for (Element el : els)
  entireText += el.text();          
在一个包含约64个元素的容器上,每个元素包含约1KB(整个文本的总容量约为64KB),在典型的低端Android手机上,这个简单的循环大约需要8秒钟

这种缓慢的性能有点让我吃惊,因为我觉得Java编译器用
新的StringBuilder(A).append(B).append(C).toString()替换了
A+B+C
这样的表达式

不是这样吗

我错过了什么

这种缓慢的表现有点让我吃惊,因为我在 Java编译器替代A+B+C等表达式的印象 使用新的StringBuilder(A).append(B).append(C).toString()

因此编译器创建代码:

for (Element el : els)
  entireText = new StringBuilder(entireText).append(el.text()).toString(); 

您需要在循环外部创建StringBuilder并手动附加到它。

这里的问题是,第一次迭代创建一个1k字符串,第二次创建一个2k字符串,第三次创建一个3k字符串

每个字符串都需要创建前一个字符串的副本。因此,您的第一次迭代复制1k文本,第二次复制2k,第三次复制3k

因此,每次迭代都比上一次慢,最后一次迭代分配64k缓冲区并复制64k


使用
StringBuilder
(如@mlk所示)意味着您几乎只需分配64k一次(不完全,但足够接近),并且只复制总共64k数据(与64k+63k+62k+61k+60k+…)相反。

您是否比较了这两个选项,或者只是猜测字符串连接是问题的根本原因?@home当然我进行了比较。StringBuilder选项在不到1秒的时间内完成这项工作。
javac
编译器几乎不进行任何优化。即使使用JIT,它也不会对代码进行太多优化。开发人员需要知道这是非常有效的。为什么不在每个迭代中向一个
StringBuilder
实例添加文本呢?对于每个迭代,您都在制作什么
新的StringBuilder
?@mlk-Ah-OK。我认为Java编译器比这更聪明。@alaster-您应该创建一个StringBuilder。我的代码是显示编译器正在做什么,而不是OP应该做什么。@Souper:它真的不能。您可以请求并构建一个
字符串
变量。编译器不能真正忽略该请求而不构建该对象。JVM理论上可以检测到,除了构建一个新字符串并创建一个
StringBuilder
之外,您从未使用过
String
,但我怀疑是否有JVM会进行这种优化。