54 java optimization string-concatenation
有人告诉我,使用StringBufferJava连接字符串比使用+运算符Strings 更有效.当你这样做时会发生什么?有什么StringBuffer不同的做法?
Cal*_*lum 62
最好使用StringBuilder(它是一个不同步的版本;你什么时候并行构建字符串?)这几天,几乎在所有情况下,但这是发生的事情:
当你使用+两个字符串时,它会编译如下代码:
String third = first + second;
Run Code Online (Sandbox Code Playgroud)
对于这样的事情:
StringBuilder builder = new StringBuilder( first );
builder.append( second );
third = builder.toString();
Run Code Online (Sandbox Code Playgroud)
因此,仅举几个例子,通常没有什么区别.但是当你构建一个复杂的字符串时,你经常需要处理更多的事情.例如,您可能正在使用许多不同的附加语句,或者像这样的循环:
for( String str : strings ) {
out += str;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,一个新的StringBuilder实例,以及一个新的String(新值out- Strings为不可变的)需要在每一次迭代.这非常浪费.用一个单位替换它StringBuilder意味着你可以只生成一个String而不用String你不关心的s来填充堆.
tko*_*zka 42
对于简单的连接,例如:
String s = "a" + "b" + "c";
Run Code Online (Sandbox Code Playgroud)
使用它是毫无意义的StringBuffer- 正如jodonnell指出的那样,它将被巧妙地翻译成:
String s = new StringBuffer().append("a").append("b").append("c").toString();
Run Code Online (Sandbox Code Playgroud)
但是在循环中连接字符串是非常不合格的,例如:
String s = "";
for (int i = 0; i < 10; i++) {
s = s + Integer.toString(i);
}
Run Code Online (Sandbox Code Playgroud)
在此循环中使用string将在内存中生成10个中间字符串对象:"0","01","012"等等.使用StringBuffer您编写相同内容时,只需更新一些内部缓冲区,StringBuffer而不创建您不需要的中间字符串对象:
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(i);
}
Run Code Online (Sandbox Code Playgroud)
实际上,对于上面的示例,您应该使用StringBuilder(在Java 1.5中引入)而不是StringBuffer- StringBuffer因为它的所有方法都是同步的,所以稍微重一些.
And*_*lla 20
一个人不应该比另一个人快.在Java 1.4.2之前不是这样,因为当使用"+"运算符连接两个以上的字符串时,String将在构建最终字符串的过程中创建中间对象.
但是,随着Java文档的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;
}
Run Code Online (Sandbox Code Playgroud)
但请记住,通常用"+"连接几个字符串比使用append()它们更清晰.
jod*_*ell 10
在引擎盖下,它实际上创建并附加到StringBuffer,在结果上调用toString().所以你使用它实际上并不重要.
所以
String s = "a" + "b" + "c";
Run Code Online (Sandbox Code Playgroud)
变
String s = new StringBuffer().append("a").append("b").append("c").toString();
Run Code Online (Sandbox Code Playgroud)
对于在单个语句中的一堆内联追加,这是正确的.如果你在多个语句的过程中构建你的字符串,那么你就是在浪费内存,而StringBuffer或StringBuilder是你更好的选择.
我认为给定jdk1.5(或更高版本)并且你的连接是线程安全的,你应该使用StringBuilder而不是StringBuffer http://java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs-stringbuilder.html 至于速度的提升:http: //www.about280.com/stringtest.html
我个人认为代码是为了可读性,所以除非你发现字符串连接使你的代码变得相当慢,否则请使用哪种方法使代码更具可读性.
在某些情况下,由于编译器执行优化,这已经过时,但一般问题是代码如下:
string myString="";
for(int i=0;i<x;i++)
{
myString += "x";
}
Run Code Online (Sandbox Code Playgroud)
将按以下方式行事(每一步都是下一个循环迭代):
如您所见,每次迭代都需要复制一个字符,导致我们在每个循环中执行1 + 2 + 3 + 4 + 5 + ... + N个操作.这是O(n ^ 2)操作.但是,如果我们事先知道我们只需要N个字符,我们可以在一次分配中完成,只使用我们使用的字符串中的N个字符的副本 - 仅仅是O(n)操作.
StringBuffer/StringBuilder避免这种情况,因为它们是可变的,因此不需要反复复制相同的数据(只要有空间可以复制到它们的内部缓冲区中).它们避免执行分配和复制,与按当前大小的比例过度分配缓冲区所做的附加次数成比例,给予摊销的O(1)追加.
然而值得注意的是,编译器通常会自动将代码优化为StringBuilder样式(或者更好 - 因为它可以执行常量折叠等).