4

全部,

我想知道使用 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 变量会如何影响性能,从而影响问题。

请倾诉你的意见

[编辑]:删除了关于与 StringBuilder 进行比较的第二个问题,因为我已经明白没有什么可以根据回复进行研究了。

4

6 回答 6

7

比连接字符串更好?

如果你问是否

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

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

在简单的情况下,例如str = "something" + "more" + "...";. 然后我可以看到的唯一性能差异是编译器没有设置初始大小的优势。基准会告诉您差异是否足够重要。不过,使用+会使代码更具可读性。

根据我的阅读,编译器显然无法优化循环中完成的连接,例如

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

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

StringBuilder 与 StringBuffer

StringBuilder虽然 is 不是线程安全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变量。

于 2010-10-31T02:43:54.857 回答
3

我只关注问题的这一部分。(其他部分之前在SO上已经被问过很多次了。)

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

这取决于您使用的 Java 类库。在一些较早的 Sun 版本的 Java 中,StringBuffer.toString() 是在假设调用sb.toString()是对缓冲区的最后一件事的情况下实现的。StringBuffer 的原始后备数组成为由toString(). 随后尝试使用 StringBuffer 导致通过复制 String 内容创建和初始化一个新的支持数组。因此,在代码尝试重用 StringBuffer 时,实际上会使应用程序变慢。

对于 Java 1.5 及更高版本,更好的编码方式如下:

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

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

最后,只有当您有证据表明这部分代码是(或可能是)瓶颈时,您才应该担心所有这些。“过早的优化是万恶之源”等等等等。

于 2010-10-31T02:47:55.590 回答
1

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

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

你也可能对这篇文章感兴趣:微优化剧场的悲惨悲剧

于 2010-10-31T02:32:58.483 回答
0

1 > 这仍然比使用 String 对象附加内容有更好的性能吗?

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

2 > 如果在这里使用 StringBuilder 会比 StringBuffer 表现更好,为什么?

您是否阅读过 StringBuilder 和/或 StringBuffer 的 API 描述?此处已发布此问题。

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

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

于 2010-10-31T02:20:44.737 回答
0

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

假设变量是方法的局部变量,或者如果在方法之外声明它不会被多个线程使用(如果它在方法之外,您的代码可能有问题)然后将其设为 StringBuilder。

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

如果在循环内声明 StringBuilder,则无需在循环结束时将长度设置为 0。

在循环之外声明它并将长度设置为 0 可能会更快,但我会同时测量两者,如果差异不大,则在循环内声明变量。限制变量的范围是一种很好的做法。

于 2010-10-31T02:46:07.673 回答
-1

对!setLength(0)是个好主意!这就是它的用途。更快的方法是丢弃stringBuffer并制作一个新的。它更快,不能说它是内存效率的:)

于 2010-10-31T05:41:13.353 回答