什么是更高效的StringBuffer new()或delete(0,sb.length())?

时间:2011-08-23 23:51:37

标签: java instance stringbuffer performance

人们常常认为避免创建对象(特别是在循环中)被认为是一种很好的做法。

那么,关于StringBuffer最有效的是什么?

StringBuffer sb = new StringBuffer();
ObjectInputStream ois = ...;

for (int i=0;i<1000;i++) {

    for (j=0;i<10;j++) {
        sb.append(ois.readUTF());
    }
    ...

    // Which option is the most efficient? 
    sb = new StringBuffer(); // new StringBuffer instance?
    sb.delete(0,sb.length()); // or deleting content?

}

我的意思是,有人可能认为创建一个对象比循环遍历数组要快。

3 个答案:

答案 0 :(得分:16)

首先StringBuffer是线程安全的,与StringBuilder相比,性能会有所下降。 StringBuilder不是线程安全的,但结果更快。最后,我更喜欢使用setLength将长度设置为0。

sb.setLength(0)

这类似于.delete(...),除非你真的不关心长度。也可能快一点,因为它不需要'删除'任何东西。创建新的StringBuilder(或StringBuffer)效率会降低。任何时候你看到new Java正在创建一个新对象并将其放在堆上。

注意:在查看.delete.setLength的实施后,.delete设置长度= 0,而.setLength将所有内容设置为'\0'所以你可以通过.delete获得一点胜利

答案 1 :(得分:3)

只是为了放大以前的评论:

从查看源代码,delete()总是调用System.arraycopy(),但如果参数是(0,count),它将调用arraycopy(),其长度为零,这可能没有效果。恕我直言,这应该进行优化,因为我敢打赌这是最常见的情况,但无论如何。

另一方面,对于setLength(),调用将通过调用ensureCapacityInternal()来增加StringBuilder的容量(另一个应该已经优化的常见情况恕我直言)然后截断delete()所需的长度。

最终,这两种方法最终都将count设置为零。

在这种情况下,两个调用都没有进行任何迭代。两者都进行不必要的函数调用。但是,ensureCapacityInternal()是一个非常简单的私有方法,它邀请编译器几乎不存在优化它,因此setLength()可能稍微更高效。

我非常怀疑创建一个新的StringBuilder实例可能会像将count设置为零一样高效,但我认为编译器可能会识别所涉及的模式将重复的实例化转换为对setLength(0)的重复调用。但在最好的情况下,这将是一个洗涤。而且你依赖于编译器来识别这种情况。

执行摘要:setLength(0)是最有效的。为了获得最大效率,请在创建时在StringBuilder中预先分配缓冲区空间。

答案 2 :(得分:1)

删除方法以这种方式实现:

public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}

正如您所看到的,它不会遍历数组。