当前位置:  开发笔记 > 编程语言 > 正文

为什么在Java中使用StringBuffer而不是字符串连接运算符

如何解决《为什么在Java中使用StringBuffer而不是字符串连接运算符》经验,为你挑选了6个好方法。

有人告诉我,使用StringBufferJava连接字符串比使用+运算符Strings 更有效.当你这样做时会发生什么?有什么StringBuffer不同的做法?



1> Calum..:

最好使用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- Strings为不可变的)需要在每一次迭代.这非常浪费.用一个单位替换它StringBuilder意味着你可以只生成一个String而不用String你不关心的s来填充堆.


为什么编译器无法对此进行优化?似乎编译器应该能够解决这个问题.

2> tkokoszka..:

对于简单的连接,例如:

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因为它的所有方法都是同步的,所以稍微重一些.


我希望"a"+"b"+"c"实际上会直接编译为"abc",而不会在运行时进行字符串连接.
@Thilo:是的,大多数java编译器实际上会将String文字的连接组合成一个文字.参见例如http://nicklothian.com/blog/2005/06/09/on-java-string-concatenation/

3> André Chalel..:

一个人不应该比另一个人快.在Java 1.4.2之前不是这样,因为当使用"+"运算符连接两个以上的字符串时,String将在构建最终字符串的过程中创建中间对象.

但是,随着Java文档的StringBuffer使用"+"操作符州,至少从Java 1.4.2编译为创建StringBufferappend()荷兰国际集团的许多字符串给它.所以没有区别,显然.

但是,在循环中使用向另一个添加字符串时要小心!例如:

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()它们更清晰.



4> jodonnell..:

在引擎盖下,它实际上创建并附加到StringBuffer,在结果上调用toString().所以你使用它实际上并不重要.

所以

String s = "a" + "b" + "c";

String s = new StringBuffer().append("a").append("b").append("c").toString();

对于在单个语句中的一堆内联追加,这是正确的.如果你在多个语句的过程中构建你的字符串,那么你就是在浪费内存,而StringBuffer或StringBuilder是你更好的选择.


那不是真的.String*literals*的连接实际上将优化为单个文字(至少是自JDK 1.4以来的Sun的javac.).如果并非所有表达式都是字符串文字,则使用StrinBuffer.

5> slipset..:

我认为给定jdk1.5(或更高版本)并且你的连接是线程安全的,你应该使用StringBuilder而不是StringBuffer http://java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs-stringbuilder.html 至于速度的提升:http: //www.about280.com/stringtest.html

我个人认为代码是为了可读性,所以除非你发现字符串连接使你的代码变得相当慢,否则请使用哪种方法使代码更具可读性.



6> Brian..:

在某些情况下,由于编译器执行优化,这已经过时,但一般问题是代码如下:

string myString="";
for(int i=0;i

将按以下方式行事(每一步都是下一个循环迭代):

    构造一个长度为1的字符串对象,值为"x"

    创建一个大小为2的新字符串对象,将旧字符串"x"复制到其中,在位置2中添加"x".

    创建一个大小为3的新字符串对象,将旧字符串"xx"复制到其中,在位置3中添加"x".

    ... 等等

如您所见,每次迭代都需要复制一个字符,导致我们在每个循环中执行1 + 2 + 3 + 4 + 5 + ... + N个操作.这是O(n ^ 2)操作.但是,如果我们事先知道我们只需要N个字符,我们可以在一次分配中完成,只使用我们使用的字符串中的N个字符的副本 - 仅仅是O(n)操作.

StringBuffer/StringBuilder避免这种情况,因为它们是可变的,因此不需要反复复制相同的数据(只要有空间可以复制到它们的内部缓冲区中).它们避免执行分配和复制,与按当前大小的比例过度分配缓冲区所做的附加次数成比例,给予摊销的O(1)追加.

然而值得注意的是,编译器通常会自动将代码优化为StringBuilder样式(或者更好 - 因为它可以执行常量折叠等).

推荐阅读
个性2402852463
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有