【发布时间】:2011-07-08 17:30:19
【问题描述】:
我在循环中使用StringBuilder,每x 次迭代我想清空它并从一个空的StringBuilder 开始,但我在文档,只是 delete 方法似乎过于复杂。
那么在 Java 中清除 StringBuilder 的最佳方法是什么?
【问题讨论】:
标签: java stringbuilder
我在循环中使用StringBuilder,每x 次迭代我想清空它并从一个空的StringBuilder 开始,但我在文档,只是 delete 方法似乎过于复杂。
那么在 Java 中清除 StringBuilder 的最佳方法是什么?
【问题讨论】:
标签: java stringbuilder
两种工作方式:
stringBuilderObj.setLength(0)。new StringBuilder() 分配一个新的,而不是清除缓冲区。请注意,对于性能关键的代码路径,这种方法可能比基于 setLength 的方法慢得多(因为需要分配带有新缓冲区的新对象,旧对象才有资格进行 GC 等)。【讨论】:
if (count < newLength),但如果newLength 为0,则永远不会发生这种情况。
基本上有两种选择,使用setLength(0) 重置 StringBuilder 或在每次迭代中创建一个新的。两者都可以根据用途各有利弊。
如果您事先知道 StringBuilder 的预期容量,那么每次创建一个新的应该和设置一个新的长度一样快。它还有助于垃圾收集器,因为每个 StringBuilder 的生命周期都相对较短,并且 gc 已为此进行了优化。
当您不知道容量时,重用相同的 StringBuilder 可能会更快。每次追加时超出容量,都必须分配一个新的后备数组,并且必须复制以前的内容。通过重用同一个StringBuilder,经过多次迭代,就可以达到需要的容量,之后就不会再有任何复制了。
【讨论】:
new 一个新的 StringBuffer 因为我希望有时我会有相当长的字符串,因此我从一个相当大的缓冲区开始(4k 或 32k) .因此,听起来 setLength(0) 可能会更快。但是 - 如果 StringBuffer 分配的空间永远不会缩小,我可能会耗尽内存(这是在 Android 下内存会变得紧张)。
trimToSize 方法释放不需要的空间。
StringBuilder 更好吗?
delete 并不过分复杂:
myStringBuilder.delete(0, myStringBuilder.length());
你也可以这样做:
myStringBuilder.setLength(0);
【讨论】:
setLength 替代方案很有趣,谢谢。
如果您查看 StringBuilder 或 StringBuffer 的源代码,setLength() 调用只会重置字符数组的索引值。恕我直言,使用 setLength 方法总是比新分配快。他们应该将方法命名为“clear”或“reset”,这样会更清晰。
【讨论】:
我会投票给sb.setLength(0);,不仅因为它是一个函数调用,而且因为它实际上并没有像sb.delete(0, builder.length()); 那样将数组复制到另一个数组中。它只是将剩余的字符填充为 0 并将长度变量设置为新的长度。
您可以查看他们的实现,以通过 here setLength 函数和 delete0 函数验证我的观点。
【讨论】:
您应该使用sb.delete(0, sb.length()) 或sb.setLength(0) 而不是创建新的StringBuilder()。
有关性能,请参阅此相关帖子:Is it better to reuse a StringBuilder in a loop?
【讨论】:
我认为这里的许多答案可能缺少StringBuilder 中包含的质量方法:.delete(int start, [int] end)。我知道这是一个迟到的答复;但是,这应该被告知(并且解释得更彻底)。
假设您有一个 StringBuilder 表 - 您希望在整个程序中动态修改它(我现在正在做的一个),例如
StringBuilder table = new StringBuilder();
如果您正在循环该方法并更改内容,请使用该内容,然后希望丢弃该内容以“清理”StringBuilder 以进行下一次迭代,您可以删除它的内容,例如
table.delete(int start, int end).
start 和 end 是您要删除的字符的索引。不知道字符的长度并想删除整个内容?
table.delete(0, table.length());
现在,为踢球者。 StringBuilders,如前所述,在频繁更改时会占用大量开销(并且可能导致线程方面的安全问题);因此,使用StringBuffer - 与StringBuilder 相同(有一些例外) - 如果您的StringBuilder 用于与用户交互的目的。
【讨论】:
StringBuilder s = new StringBuilder();
s.append("a");
s.append("a");
// System.out.print(s); is return "aa"
s.delete(0, s.length());
System.out.print(s.length()); // is return 0
是最简单的方法。
【讨论】:
如果性能是主要关注点,那么讽刺的是,在我看来,用于格式化 进入 缓冲区的文本的 Java 构造在 CPU 上的耗时将远远超过分配时间/reallocation/garbage collection ...好吧,可能不是 GC(垃圾回收),具体取决于您创建和丢弃的构建器数量。
但简单地将复合字符串 ("Hello World of " + 6E9 + " earthlings.") 附加到缓冲区可能会使整个问题变得无关紧要。
而且,实际上,如果涉及StringBuilder 的实例,那么内容会比简单的String str = "Hi"; 复杂和/或更长(不管Java 可能在后台使用构建器)。
就我个人而言,我尽量不滥用 GC。因此,如果它在快速触发场景中会被大量使用——比如编写调试输出消息——我只是假设在其他地方声明它并将其归零以供重用。
class MyLogger {
StringBuilder strBldr = new StringBuilder(256);
public void logMsg( String stuff, SomeLogWriterClass log ) {
// zero out strBldr's internal index count, not every
// index in strBldr's internal buffer
strBldr.setLength(0);
// ... append status level
strBldr.append("Info");
// ... append ' ' followed by timestamp
// assuming getTimestamp() returns a String
strBldr.append(' ').append(getTimestamp());
// ... append ':' followed by user message
strBldr.append(':').append(msg);
log.write(strBldr.toString());
}
}
【讨论】:
strBldr.trimToSize(); 将在设置长度后释放所有未使用的空间。不幸的是,如果经常使用该对象,只会导致内存流失,因此最好在.setLength(0) 之前使用它,而不是之后使用它。