Java:清除StringBuffer内容

时间:2010-10-31 02:02:04

标签: java stringbuilder stringbuffer

所有

我想知道使用setLength(0)清除StringBuffer内容是否有意义。即,做得更好:

while (<some condition>)
{
    stringBufferVariable = new StringBuffer(128);
    stringBufferVariable.append(<something>)
                        .append(<more>)
                        ... ;
    Append stringBufferVariable.toString() to a file;
    stringBufferVariable.setLength(0);
}

我的问题:
1>这还有比使用String对象追加内容更好的性能吗?

我不确定如何重新初始化StringBuffer变量会影响性能,从而影响问题。

请填写您的意见

[edit]:删除了关于与StringBuilder进行比较的第二个问题,因为我已经理解根据响应没有其他内容可以研究。

6 个答案:

答案 0 :(得分:7)

比连接字符串好吗?

如果你问是否

stringBufferVariable.append("something")
                    .append("more");
...

将比与+连接更好,然后通常是。这就是这些类存在的全部原因。与更新char数组中的值相比,对象创建非常昂贵。

在大多数情况下,如果不是所有编译器现在都将字符串连接转换为在str = "something" + "more" + "...";这样的简单情况下使用StringBuilder。我可以看到的唯一性能差异是编译器没有设置初始大小的优势。基准测试将告诉您差异是否足够重要。使用+会使代码更易读。

从我读过的内容来看,编译器显然不能优化循环中的连接,就像

一样
String str = "";
for (int i = 0; i < 10000; i++) {
    str = str + i + ",";
}

因此,在这些情况下,您仍然希望显式使用StringBuilder。

StringBuilder vs StringBuffer

StringBuilder是{p> StringBuffer不是线程安全的,但它们在其他方面是相同的。在StringBuffer中执行的同步使其更慢,因此StringBuilder更快,除非您需要同步,否则应该使用它。

您应该使用setLength吗?

您的示例当前编写的方式我不认为对setLength的调用会给您带来任何好处,因为您在每次循环中都创建了一个新的StringBuffer。你真正应该做的是

StringBuilder sb = new StringBuilder(128);
while (<some condition>) {
    sb.append(<something>)
      .append(<more>)
      ... ;
    // Append stringBufferVariable.toString() to a file;
    sb.setLength(0);
}

这可以避免不必要的对象创建,setLength只会在这种情况下更新内部int变量。

答案 1 :(得分:3)

我只关注这部分问题。 (之前已经多次询问并回答了其他部分。)

  

我想知道使用setLength(0)清除StringBuffer内容是否有意义。

这取决于您使用的Java类库。在Java的一些较旧的Sun版本中,StringBuffer.toString()是在假设调用sb.toString()是缓冲区完成的最后一件事的情况下实现的。 StringBuffer的原始后备数组成为toString()返回的String的一部分。随后尝试使用StringBuffer导致通过复制String内容创建并初始化新的后备阵列。因此,重用StringBuffer就像你的代码试图做的那样实际上会使应用程序变慢。

使用Java 1.5及更高版本,更好的编码方法如下:

    bufferedWriter.append(stringBufferVariable);
    stringBufferVariable.setLength(0);

这应该直接将StringBuilder中的字符复制到文件缓冲区中,而无需创建临时String。假设StringBuffer声明在循环之外,则setLength(0)允许您重用缓冲区。

最后,如果您有证据证明这部分代码是(或可能是)瓶颈,那么您应该只担心所有这些。 “过早的优化是所有邪恶的根源”,等等,等等。

答案 2 :(得分:1)

对于问题2,StringBuilder的性能优于StringBuffer。 StringBuffer是线程安全的,意味着方法是同步的。字符串生成器未同步。因此,如果您拥有的代码将由一个线程运行,那么StringBuilder将具有更好的性能,因为它没有执行同步的开销。

正如camickr建议的那样,请查看StringBuffer和StringBuilder的API以获取更多信息。

您也可能对这篇文章感兴趣:The Sad Tragedy of Micro-Optimization Theater

答案 3 :(得分:0)

  

1&gt;这还有比使用String对象附加内容更好的性能吗?

是的,因为你不断创建新的字符串对象,所以连接字符串很慢。

  

2&gt;如果在这里使用StringBuilder会比StringBuffer更好,那么为什么呢?

您是否阅读过StringBuilder和/或StringBuffer的API描述?这是在那里发布的。

  

我不确定如何重新初始化StringBuffer变量会影响性能,从而影响问题。

好好创建一个测试程序。创建一个每次都创建一个新StringBuffer / Builder的测试。然后重新运行测试,只需将字符重置为0,然后比较时间。

答案 4 :(得分:0)

也许我在你的问题中误解了一些内容...如果你只是在每次迭代开始时创建一个新的长度,为什么你将长度设置为0?

假设变量是方法的局部变量,或者如果多个线程在方法之外声明它将不会被多个线程使用(如果它在方法之外,你的代码可能有问题),那么就把它变成一个StringBuilder的。

如果在循环之外声明StringBuilder,那么每次进入循环时都不需要创建一个新的,但是你想在循环结束时将长度设置为0。

如果在循环内部声明StringBuilder,则不需要在循环结束时将长度设置为0.

很可能在循环外声明并将长度设置为0会更快,但我会测量两者,如果没有大的差异,则在循环内声明变量。优良作法是限制变量的范围。

答案 5 :(得分:-1)

烨! setLength(0)是个好主意!这就是它的用途。更快捷的做法是放弃stringBuffer&amp;做一个新的。它的速度更快,无法说出内存效率:)