有人告诉我,使用StringBuffer
连接Java中的字符串比使用+
String
运算符更有效率。当你这样做时会发生什么? StringBuffer
做什么不同?
答案 0 :(得分:61)
最好使用StringBuilder(它是一个不同步的版本;你什么时候并行构建字符串?)这几天,几乎在所有情况下,但这是发生的事情:
当你对两个字符串使用+时,它会编译如下代码:
String third = first + second;
对于这样的事情:
StringBuilder builder = new StringBuilder( first );
builder.append( second );
third = builder.toString();
因此,仅举几个例子,它通常没有什么区别。但是当你构建一个复杂的字符串时,你经常需要处理的事情比这更多;例如,您可能正在使用许多不同的附加语句,或者像这样的循环:
for( String str : strings ) {
out += str;
}
在这种情况下,每次迭代都需要一个新的StringBuilder
实例和一个新的String
(out
- String
的新值是不可变的)。这非常浪费。用单个StringBuilder
替换它意味着您只需生成一个String
而不用{0}你不关心的堆填充堆。
答案 1 :(得分:42)
对于简单的连接,例如:
String s = "a" + "b" + "c";
使用StringBuffer
毫无意义 - 因为 jodonnell 指出它将被巧妙地翻译成:
String s = new StringBuffer().append("a").append("b").append("c").toString();
但是在循环中连接字符串非常缺乏,例如:
String s = "";
for (int i = 0; i < 10; i++) {
s = s + Integer.toString(i);
}
在此循环中使用string将在内存中生成10个中间字符串对象:“0”,“01”,“012”等等。使用StringBuffer
编写相同内容时,只需更新StringBuffer
的某个内部缓冲区,并且不创建那些不需要的中间字符串对象:
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(i);
}
实际上,对于上面的示例,您应该使用StringBuilder
(在Java 1.5中引入)而不是StringBuffer
- StringBuffer
稍微重一点,因为它的所有方法都是同步的。
答案 2 :(得分:20)
一个人不应该比另一个人快。在Java 1.4.2之前不是这样,因为当使用“+”运算符连接两个以上的字符串时,将在构建最终字符串的过程中创建中间String
个对象。
然而,正如JavaDoc for StringBuffer所述,至少从使用“+”运算符的Java 1.4.2开始编译为向其创建StringBuffer
和append()
多个字符串。所以没有区别,显然。
但是,在循环中使用向另一个添加字符串时要小心!例如:
String myString = "";
for (String s : listOfStrings) {
// Be careful! You're creating one intermediate String object
// for every iteration on the list (this is costly!)
myString += s;
}
但请注意,通常将一些字符串与“+”连接起来比append()
更加清晰。
答案 3 :(得分:9)
在引擎盖下,它实际上创建并附加到StringBuffer,在结果上调用toString()。所以你使用它实际上并不重要。
所以
String s = "a" + "b" + "c";
变为
String s = new StringBuffer().append("a").append("b").append("c").toString();
对于在单个语句中的一堆内联追加,这是正确的。如果你在多个语句的过程中构建字符串,那么你就是在浪费内存,而StringBuffer或StringBuilder是你更好的选择。
答案 4 :(得分:7)
我认为给定jdk1.5(或更高版本)并且你的连接是线程安全的,你应该使用StringBuilder而不是StringBuffer http://java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs-stringbuilder.html 至于速度的提升: http://www.about280.com/stringtest.html
就我个人而言,我的代码是为了便于阅读,所以除非你发现字符串连接使你的代码相当慢,否则请使用哪种方法使代码更具可读性。
答案 5 :(得分:5)
在某些情况下,由于编译器执行了优化,这已经过时,但一般问题是代码如下:
string myString="";
for(int i=0;i<x;i++)
{
myString += "x";
}
将如下所示(每一步都是下一个循环迭代):
如您所见,每次迭代都要复制一个字符,导致我们在每个循环中执行1 + 2 + 3 + 4 + 5 + ... + N个操作。这是O(n ^ 2)操作。但是,如果我们事先知道我们只需要N个字符,我们可以在一次分配中完成,只使用我们使用的字符串中只有N个字符的副本 - 仅仅是O(n)操作。
StringBuffer / StringBuilder避免这种情况,因为它们是可变的,因此不需要反复复制相同的数据(只要有空间可以复制到其内部缓冲区中)。他们避免执行分配和复制,与按当前大小的一部分过度分配缓冲区所做的附加次数成比例,给予摊销的O(1)追加。
然而值得注意的是,编译器通常会自动将代码优化为StringBuilder样式(或更好 - 因为它可以执行常量折叠等)。
答案 6 :(得分:3)
Java将string1 + string2转换为StringBuffer构造,append()和toString()。这是有道理的。
但是,在Java 1.4及更早版本中,它将在语句中单独为每个 +运算符执行此操作。这意味着执行+ b + c将导致两个 StringBuffer构造与两个 toString()调用。如果你有一长串的concats,它将变成一个真正的混乱。自己动手意味着你可以控制它并正确地完成它。
Java 5.0及更高版本似乎更明智地做到了,所以它不是一个问题,而且肯定不那么冗长。
答案 7 :(得分:3)
AFAIK它依赖于JVM的版本,在1.5之前的版本中使用“+”或“+ =”实际上每次都复制了整个字符串。
注意使用+ =实际分配新的字符串副本。
正如使用+ in循环指向复制。
当被连接的字符串是编译时常量时,它们在编译时连接,所以
String foo = "a" + "b" + "c";
已编译为:
String foo = "abc";
答案 8 :(得分:1)
因为字符串是不可变的,所以每次调用+运算符都会创建一个新的String对象,并将String数据复制到新的String。由于复制String在String的长度上需要线性时间,因此对+运算符的N个调用序列会导致O(N 2 )运行时间(二次)。
相反,由于StringBuffer是可变的,因此每次执行Append()时都不需要复制String,因此N Append()调用序列需要O(N)时间(线性)。如果要将大量字符串附加在一起,这只会在运行时产生显着差异。
答案 9 :(得分:1)
更多信息:
StringBuffer是一个线程安全的类
public final class StringBuffer extends AbstractStringBuilder
implements Serializable, CharSequence
{
// .. skip ..
public synchronized StringBuffer append(StringBuffer stringbuffer)
{
super.append(stringbuffer);
return this;
}
// .. skip ..
}
但StringBuilder不是线程安全的,因此如果可能的话,使用StringBuilder会更快
public final class StringBuilder extends AbstractStringBuilder
implements Serializable, CharSequence
{
// .. skip ..
public StringBuilder append(String s)
{
super.append(s);
return this;
}
// .. skip ..
}
答案 10 :(得分:1)
当您连接两个字符串时,实际上是在Java中创建第三个String对象。使用StringBuffer(或Java 5/6中的StringBuilder)更快,因为它使用内部字符数组来存储字符串,当你使用其中一个add(...)方法时,它不会创建新的字符串宾语。而是,StringBuffer / Buider附加内部数组。
在简单的连接中,使用StringBuffer / Builder或'+'运算符连接字符串并不是一个真正的问题,但是在进行大量字符串连接时,您会发现使用StringBuffer / Builder更快。
答案 11 :(得分:1)
如上所述,String对象是不可变的,这意味着一旦创建它(见下文)就无法更改。
String x = new String(“something”); //或
字符串x =“某事”;
因此,当您尝试连接String对象时,将获取这些对象的值并将其放入新的String对象中。
如果您改为使用可变的StringBuffer,则不断将值添加到char(基元)的内部列表中,可以对其进行扩展或截断以适应所需的值。没有创建新对象,只需要在保存值时创建/删除新的char。
答案 12 :(得分:1)
StringBuffer类维护一个字符数组来保存你连接的字符串的内容,而+方法每次调用时都会创建一个新字符串并附加两个参数(param1 + param2)。
StringBuffer更快,因为1.它可能能够使用其现有的数组来连接/存储所有字符串。 2.即使它们不适合数组,也可以更快地分配更大的后备数组,然后为每次调用生成新的String对象。
答案 13 :(得分:1)
要使用'+'连接两个字符串,需要为两个字符串分配一个新字符串,然后从两个字符串复制数据。 StringBuffer针对连接进行了优化,并且最初分配的空间超出了所需的空间。连接新字符串时,在大多数情况下,可以简单地将字符复制到现有字符串缓冲区的末尾 为了连接两个字符串,'+'运算符可能会有更少的开销,但是当你连接更多的字符串时,StringBuffer将提前出现,使用更少的内存分配,减少数据复制。
答案 14 :(得分:1)
StringBuffer是可变的。它将字符串的值添加到相同的对象,而不实例化另一个对象。做类似的事情:
myString = myString + "XYZ"
将创建一个 new String对象。
答案 15 :(得分:0)
Java语言规范的String Concatenation Operator +部分为您提供了有关+运算符为何如此慢的原因的更多背景信息。
答案 16 :(得分:0)
我认为最简单的答案是:它更快。
如果你真的想知道所有引擎盖下的内容,你可以随时查看来源:
答案 17 :(得分:0)
因为字符串在Java中是不可变的,所以每次连接字符串时,都会在内存中创建新对象。 StringBuffer在内存中使用相同的对象。
答案 18 :(得分:0)
原因是字符串不可变。它创建一个新的字符串,而不是修改字符串。
字符串池存储所有字符串值,直到垃圾回收器将其值加长。
考虑一下两个字符串,分别为Hello
和how are you
。
如果我们考虑字符串池,它有两个字符串。
如果您尝试将这两个字符串串联在一起,
string1 =字符串1+字符串2
现在创建一个新的String对象并将其存储在String池中。
如果我们尝试连接上千个单词,它将获得更多的内存。解决方案是StringBuilder或StringBuffer。只能创建一个对象,并且可以对其进行修改。因为两者都是可变的,所以不需要更多的内存。如果您认为线程安全,则使用StringBuffer,否则使用StringBuilder。
public class StringExample {
public static void main(String args[]) {
String arr[] = {"private", "default", "protected", "public"};
StringBuilder sb= new StringBuilder();
for (String value : arr) {
sb.append(value).append(" ");
}
System.out.println(sb);
}
}
输出:私有默认受保护的公共