一般来说,在Java中使用Encx1与0的字符串连接是最好的。情况总是这样吗?
我的意思是:创建一个StringBuilder对象的开销,调用append()方法,最后调用toString()已经更小了,然后将现有的字符串与+运算符连接起来作为两个字符串,还是只建议使用两个以上的字符串?
如果有这样一个阈值,它依赖于什么(也许是字符串长度,但以何种方式)?
最后,您是否愿意将+连接的可读性和简洁性与StringBuilder在较小的情况下(如两个、三个或四个字符串)的性能进行权衡?
在常规的连接优化中,使用EDCOX1的0度是过时的Java优化技巧以及Java城市神话。
- 有关详细说明,请参阅此博客文章:rationaljava.com/2015/02/the-optimize-method-to-c‌&8203;oncatenate.html
如果在循环中使用字符串串联,类似于这样,
1 2 3 4
| String s ="";
for (int i = 0; i < 100; i ++) {
s +="," + i ;
} |
然后,您应该使用EDOCX1(不是StringBuffer)而不是String,因为它更快,占用的内存更少。
如果你只有一句话,
1
| String s ="1," +"2," +"3," +"4," ... ; |
号
然后您可以使用String,因为编译器将自动使用StringBuilder。
- 谢谢你,拉尔夫。简短、精确(有例子)
- 事实上,现在我真的几乎从不使用任何东西,除了弦。我曾经倡导过这些,但是随着JVM的发展,它几乎不再是必要的了,幸运的是。如果您看到上面的字节码(至少在jdk>1.6u22的情况下),您会发现所有内容都被一个StringBuilder替换了。它不再是单个语句,而是相当复杂的构造。我刚刚在现实代码上做了几个测试案例,实际上我没有发现任何情况下它在内部不使用StringBuilder。挺好的。
- @海林:你是舒尔吗?-我已经用1.6.0.21版检查过它,当然字符串循环使用一个字符串生成器来,但只用于具体化(s+=",+i;)—因此它为每个循环创建了一个新的字符串生成器!-因此,它比使用一个StringBuilder要慢得多,它是在循环的外侧创建的,在循环中只调用其append方法。
- @海林:你证明了你的论文吗?
- @拉尔夫:我尽量记住星期一把这个发出去。我使用生成的字节码进行了不同的测试。
- @拉尔夫:事实上,我刚刚在我的机器上尝试了1.6.0_18和1.6.0_24,它确实为每个循环生成了一个StringBuilder。要么我创建了一个非常具体的测试场景,在我的办公室里是有利的,要么我错了。但在大多数情况下,我想这对我来说仍然没有多大意义,在大多数情况下这并不是一个显著的性能(除了相当长的紧密循环和构建相当大的字符串,例如,可能用于生成文档、XML数据或模板化目的)。正常的用例只是太多的样板文件。但你就在上面。
- @拉尔夫:对不起,这一周很忙,但我终于有空把它挖出来了,正如前面提到的,我的确错了。它确实为每个循环回合创建了一个StringBuilder。真倒霉。我可以看到这样更好的情况,但我认为他们可以检测到一些情况,在这些情况下他们可以实现增强的路径检测。所以还有改进的空间:)。谢谢你让我验证一下。
- @哈莱姆:没问题
- 伟大的拉尔夫!您还可以添加引用的链接吗?
- s.concat(",").concat(i)出了什么问题?
- ViniciusPires:这个问题是关于性能的,s.concat(",").concat(i)创建了相同的结果,但是它也为每个循环迭代创建了2个新的字符串对象,这使得它变慢了。
- 尽管如此,@haylem是对的,我已经写了一个示例性能基准来证明他的声明blog.loxal.net/2014/11/&hellip;当然,简单化等等……但是区别还是很明显的:)
- @亚历山大奥洛夫:看看字节码
- @拉尔夫,你用JDK 1.8检查过这个吗?我也很好奇您如何查看字节代码,并看到它为每个循环创建了一个字符串生成器。
- @QED:我还没有检查过1.8版Oracle的javac或1.9版的预览版。如果你想试一试,你可以简单地使用javap工具来完成这个任务,并查看说明。很容易为一个简单的测试用例找到答案。我之前已经保存了一个,如果我找到它,我会在这里报告,但是(正如我最近在SE网站上缺乏活动显示的那样),我的时间非常有限。
- @QED-我使用了标准的Eclipse,没有任何附加插件:-我编译了一个示例progam,只将类文件移动到一个新项目中,并在那里打开了类文件-然后Eclipse显示了字节代码。-我还没有用JDK 1.8这样做,但是我很确定,它仍然是一样的,所以没有人阻止你用Java 8测试它。
- 我用JDK 1.8.0进行了测试——它是相同的字节代码。另外,由于对象分配现在很便宜,我对性能的大幅提高也有点怀疑。但是,切换到显式StringBuilder 1实例在1000次迭代中从~120ms给了我0-1ms的时间。因此,在类似情况下,对于关键位置,StringBuilder仍然是必需的。
- 这个示例与StringBuilder相同吗?!for(int i = 0; i < 100; i++) { final String s ="1," +"2," +"3," +"4," ....; }。
- 字符串将由StringBuilder具体化,因为它是一个单独的语句-for循环在该示例中没有意义(,它只运行了100次单语句)。
- 在现实生活中,我不得不修改内存中的一个10MB的HTML文档,并将其发送给客户机。我构建了一个字符串更改表,并使用StringBuilder构建了结果,因为我要做很多复杂的更改。幼稚的String + String的加速是巨大的,最终结果可以在10秒内处理HTML。更改表需要进行数千到数万次更改,因此创建和销毁这么多自动StringBuilder对象的开销是巨大的。
拉尔夫的回答令人难以置信。我宁愿使用StringBuilder类来构建/修饰字符串,因为它的使用更像是构建器模式。
1 2 3 4 5 6 7
| public String decorateTheString (String orgStr ){
StringBuilder builder = new StringBuilder ();
builder. append(orgStr );
builder. deleteCharAt(orgStr. length()-1);
builder. insert(0,builder. hashCode());
return builder. toString();
} |
它可以用作帮助器/生成器来构建字符串,而不是字符串本身。
- 我认为StringBuilder与构建器模式没有任何关系。名字匹配是巧合,阿法克。
- 为什么要将生成器模式与字符串生成器混合在一起?我想你是在解释编码的最佳实践。
- 为什么这个答案被否决了一次?建议的示例错误地使用了StringBuilder(大小虽然已知但未预先分配,但insert会复制数组)。这比+运算符更好吗?不回答操作
作为一般规则,总是使用更可读的代码,并且只有在性能有问题时才重构代码。在这种特定的情况下,最新的JDK实际上会在任何情况下将代码优化为StringBuilder版本。
通常,只有在循环或编译器无法轻松优化的复杂代码中执行字符串连接时,才真正需要手动执行。
请看:http://www.javaspecialists.eu/archive/issue068.html和http://www.javaspecialists.eu/archive/issue105.html
在您的环境中执行相同的测试,并检查更新的JDK或Java实现是否使用EDOCX1·0更好地使用某种类型的字符串操作,或者更好地使用EDCOX1(1)。
某些编译器不能用StringBuilder等效项替换任何字符串连接。在依赖编译时优化之前,一定要考虑源代码将使用哪些编译器。
- 有趣的是,我不知道。你能提供一个参考,哪个编译器代替连接,哪个不?
- 不,我没有那个信息。我只是说,请注意依赖编译时优化。如果你是积极的,你需要的所有编译器都提供了一定的优化,太好了!如果没有,最好假设他们没有,但最重要的是,只优化需要优化的内容。
对于两个字符串concat更快,在其他情况下,stringbuilder是更好的选择,请参阅concatenation operator(+)与concat()中的说明。
+运算符在内部使用public String concat(String str)。此方法复制两个字符串的字符,因此它具有与两个字符串长度成比例的内存需求和运行时复杂性。StringBuilder的工作效率更高。
不过,我在这里读到,使用+操作符的连接代码在后Java 4编译器上被更改为StrugBuudor。所以这可能根本不是问题。(不过,如果我在代码中依赖于此语句,我会检查它!)
字符串串联的问题是,它会导致复制字符串对象,并产生所有相关的成本。StringBuilder不是线程安全的,因此比StrugBuffy更快,这是Java 5之前首选的选择。根据经验,不应该在循环中进行字符串连接,这将经常被调用。我想在这里做一些连接不会伤害到您,只要您不谈论数百个,这当然取决于您的性能需求。如果你在做实时的事情,你应该非常小心。
微软认证材料也解决了这个问题。在.NET世界中,StringBuilder对象的开销使得2个字符串对象的简单连接更加高效。对于Java字符串,我会给出类似的答案。
- 我猜性能的影响是减轻了编译器优化类似于Java,或认证材料意味着一个有效的区别?
- 材料明确指出,在1个或2个连接(分别是2个或3个字符串)的情况下,使用StringBuilder是效率较低的实现。
- 那么,似乎与Java不同。无论如何谢谢你