简体   繁体   English

Java编译器为字符串连接构建低效的代码?

[英]Java compiler builds inefficient code for string concatination?

I thought that this is the most efficient way to concatinate strings 我认为这是结合字符串的最有效方法

new StringBuilder(s1.length() + s2.length() + s3.length()).append(s1).append(s2).append(s3).toString();

here StringBuilder's buffer is created with the capacity enough to fit all strings in it, otherwise StringBuilder may need to expand the buffer up to 3 times. 这里创建了StringBuilder的缓冲区,其容量足以容纳其中的所有字符串,否则StringBuilder可能需要将缓冲区扩展最多3次。

But when I compile / decompile this 但是当我编译/反编译时

String s4 = s1 + s2 + s3;

I get the actual code in .class built by javac (1.7.0_03) as 我得到了由javac(1.7.0_03)构建的.class中的实际代码

String s4 = (new StringBuilder(String.valueOf(s1))).append(s2).append(s3).toString();

Which way is more efficient? 哪种方式更有效?

UPDATE UPDATE

As it was suggested by Steven Schlansker, here is a performance test 正如Steven Schlansker所说,这是一次性能测试

                String s1 = "0123456789";
                String s2 = s1 + s1 + s1;
                String s3 = s1 + s1 + s1 + s1 + s1 + s1;
                long t0 = System.currentTimeMillis();
                for (int i = 0; i < 500000; i++) {

                String s4 = new StringBuilder(s1.length() + s2.length() + s3.length()).append(s1).append(s2).append(s3).toString();

//          String s4 = s1 + s2 + s3;

                }
                System.out.println(System.currentTimeMillis() - t0);

it's not perfect, but the results seem to prove that my version is ~30% faster. 它并不完美,但结果似乎证明我的版本速度提高了约30%。 On my notebook (Celeron 925) it gives ~230 ms for ver.1 aganist ~300 ms for ver.2. 在我的笔记本(Celeron 925)上,它为ver.1 aganist提供~230 ms,为ver.2提供300 ms。 Actually this is what I expected. 实际上这是我的预期。 So I think it would be a good idea if javac compiled string concatination in a more efficient way. 所以我认为如果javac以更有效的方式编译字符串连接将是一个好主意。 There are enough lines like 有足够的线条像

return "\\Q" + s + "\\E";

even in JDK classes. 甚至在JDK课程中。 The last line is from java.util.Pattern which is designed for efficiency 最后一行来自java.util.Pattern,它是为提高效率而设计的

Depends on the environment you execute it in. It's not possible to conclude definitely that one is better than the other without some sort of test. 取决于你执行它的环境。如果没有某种测试,不可能肯定地得出一个比另一个更好的结论。

That said, I agree that it's likely that knowing the final size ahead of time will provide some benefit. 也就是说,我同意提前知道最终尺寸可能会带来一些好处。

I suspect that if you write a microbenchmark, you'll find that the difference is absolutely trivial in almost any application. 我怀疑如果你写一个微基准测试,你会发现差异在几乎所有应用中都是微不足道的。

EDIT FOR BENCHMARK ADVICE: 编辑基准建议:

I see you've added some actual data to your post. 我看到你在帖子中添加了一些实际数据。 Congratulations! 恭喜! You're on the right track :-) 你走在正确的轨道上:-)

Unfortunately, Java has many features which are hostile to writing correct benchmarks. 不幸的是,Java有许多功能,这些功能对于编写正确的基准测试是不利的。 You should probably take a look at How do I write a correct micro-benchmark in Java? 您应该看一下如何在Java中编写正确的微基准测试? if you want your results to be accurate. 如果你想让你的结果准确。 It's also worth considering that speedups that look large in this context will look much smaller in the context of a "real" program. 同样值得考虑的是,在这种情况下看起来很大的加速比在“真实”程序的背景下看起来要小得多。 A single database fetch (measured in milliseconds) could easily make any gains in memory allocation completely uninteresting (measured in nanoseconds). 单个数据库提取(以毫秒为单位)可以轻松地使内存分配中的任何增益完全不感兴趣(以纳秒为单位)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM