关于Java中的字符串连接:Java中的字符串连接 – 何时使用+,StringBuilder和concat

String concatenation in Java - when to use +, StringBuilder and concat

本问题已经有最佳答案,请猛点这里访问。

什么时候我们应该使用+来连接字符串,什么时候首选StringBuilder?何时适合使用concat。

我听说StringBuilder更适合循环中的连接。 为什么会这样?

谢谢。


现代Java编译器通过StringBuilder的追加转换你的+操作。我的意思是说如果你做str = str1 + str2 + str3那么编译器将生成以下代码:

1
2
StringBuilder sb = new StringBuilder();
str = sb.append(str1).append(str2).append(str3).toString();

您可以使用DJ或Cavaj反编译代码来确认:)
所以现在使用+或StringBuilder更多的是选择而不是性能优势:)

但是考虑到编译器没有为你做这种情况(如果你使用任何私有Java SDK来实现它,那么它可能会发生),那么当你最终避免使用大量不必要的String对象时,StringBuilder肯定是可行的。 。


我倾向于在性能受到关注的代码路径上使用StringBuilder。循环内的重复字符串连接通常是一个很好的候选者。

更喜欢StringBuilder的原因是每次调用它们时+concat都会创建一个新对象(前提是右侧参数不为空)。这可以很快加起来很多对象,几乎所有对象都是完全没必要的。

正如其他人所指出的那样,当你在同一个语句中多次使用+时,编译器通常可以为你优化这个。但是,根据我的经验,当连接发生在单独的语句中时,此参数不适用。它肯定对循环没有帮助。

说完这一切之后,我认为最重要的应该是编写清晰的代码。有一些很棒的分析工具可用于Java(我使用YourKit),这使得很容易找出性能瓶颈并优化重要的位。

附:我从来不需要使用concat


来自Java / J2EE Job Interview Companion:

String

String is immutable: you can’t modify a String object but can replace it by creating a new instance. Creating a new instance is rather expensive.

1
2
3
4
5
6
7
//Inefficient version using immutable String
String output ="Some text";
int count = 100;
for (int i = 0; i < count; i++) {
    output += i;
}
return output;

The above code would build 99 new String objects, of which 98 would be thrown away immediately. Creating new objects is not efficient.

StringBuffer/StringBuilder

StringBuffer is mutable: use StringBuffer or StringBuilder when you want to modify the contents. StringBuilder was added in Java 5 and it is identical in all respects to StringBuffer except that it is not synchronised, which makes it slightly faster at the cost of not being thread-safe.

1
2
3
4
5
6
7
//More efficient version using mutable StringBuffer
StringBuffer output = new StringBuffer(110);
output.append("Some text");
for (int i = 0; i < count; i++) {
  output.append(i);
}
return output.toString();

The above code creates only two new objects, the StringBuffer and the final String that is returned. StringBuffer expands as needed, which is costly however, so it would be better to initialise the StringBuffer with the correct size from the start as shown.


如果所有连接元素都是常量(例如:"these" +"are" +"constants"),那么我更喜欢+,因为编译器会为你内联连接。否则,使用StringBuilder是最有效的方法。

如果对非常量使用+,编译器也将在内部使用StringBuilder,但调试变得很糟糕,因为使用的代码不再与源代码相同。


我的建议如下:

  • +:在连接2或3个字符串时使用,只是为了使代码简洁易读。
  • StringBuilder:在构建复杂的String输出或性能受到关注时使用。
  • String.format:你没有在你的问题中提到这个,但它是我创建字符串的首选方法,因为它使代码在我看来最可读/最简洁,对日志语句特别有用。
  • concat:我认为我没有理由使用它。

我建议使用concat进行两个字符串连接和StringBuilder,否则请参阅我对连接运算符(+)vs concat()的解释


对单个语句使用+,对多个语句/循环使用StringBuilder。


编译器的性能增益适用于连接常量。
其余的使用实际上比直接使用StringBuilder慢。

使用"+"没有问题,例如用于为Exception创建消息,因为它不经常发生,并且应用程序已经在某种程度上已经被搞砸了。避免在循环中使用"+"。

对于创建有意义的消息或其他参数化字符串(例如Xpath表达式),请使用String.format - 它的可读性更好。


如果进行大量操作,请使用StringBuilder。通常循环是一个很好的指示。

这样做的原因是使用正常级联产生许多中间String对象,这些对象不容易"扩展"(即每个连接操作产生一个副本,需要内存和CPU时间)。另一方面,StringBuilder只需要在某些情况下复制数据(在中间插入一些东西,或者因为结果变大而不得不调整大小),因此它可以节省那些复制操作。

使用concat()与使用+相比没有什么好处(对于单个+,它可能会稍微快一点,但是一旦你执行a.concat(b).concat(c),它实际上会慢于a + b + c)。