14

人们经常争辩说,避免创建对象(尤其是在循环中)被认为是好的做法。

那么,什么是最有效的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?

}

我的意思是,有人可能会争辩说,创建对象比遍历数组更快。

4

3 回答 3

16

首先StringBuffer是线程安全的,与StringBuilder. StringBuilder 不是线程安全的,但速度更快。最后,我更喜欢使用setLength将长度设置为 0 。

sb.setLength(0)

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

注意:在查看 and 的实现之后.delete.setLength设置.delete长度 = 0,并将.setLength每件事都设置为'\0'所以你可能会得到一点胜利.delete

于 2011-08-23T23:57:26.763 回答
3

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

从源码看,delete()总是调用System.arraycopy(),但是如果参数是(0,count),它会调用arraycopy长度为零的(),想必是没有效果的。恕我直言,这应该被优化,因为我敢打赌这是最常见的情况,但没关系。

setLength另一方面,使用() 时,调用将在必要时通过调用ensureCapacityInternal() 来增加 StringBuilder 的容量(另一种非常常见的情况,应该在恕我直言中优化),然后像delete() 那样截断长度。

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

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

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

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

于 2012-07-06T01:43:49.553 回答
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;
}

如您所见,它不会遍历数组。

于 2011-08-24T00:04:48.370 回答