Что более эффективно StringBuffer new() или delete (0, sb.length())?

Часто утверждается, что избегать создания объектов (особенно в циклах) считается хорошей практикой.

Тогда, что наиболее эффективно в отношении 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?

}

Я имею в виду, можно утверждать, что создание объекта происходит быстрее, чем цикл через массив.

Ответ 1

Первый StringBuffer является потокобезопасным, который будет иметь плохую производительность по сравнению с StringBuilder. StringBuilder не является потокобезопасным, но, как результат, быстрее. Наконец, я предпочитаю просто установить длину в 0, используя setLength.

sb.setLength(0)

Это похоже на .delete(...), за исключением того, что вы не заботитесь о длине. Также, вероятно, немного быстрее, так как не нужно "удалять" что-либо. Создание нового StringBuilder (или StringBuffer) было бы менее эффективным. Каждый раз, когда вы видите new Java, создается новый объект и помещается в кучу.

Примечание. Посмотрев на реализацию .delete и .setLength, .delete устанавливает length = 0, а .setLength устанавливает каждую вещь в '\0'. Таким образом, вы можете получить немного выиграть с .delete

Ответ 2

Просто чтобы усилить предыдущие комментарии:

От взгляда на источник delete() всегда вызывает System.arraycopy(), но если аргументы (0, count), он будет вызывать arraycopy() с длиной нуля, которая, предположительно, будет иметь нет эффекта. IMHO, это должно быть оптимизировано, так как я ставлю его наиболее распространенным случаем, но неважно.

С setLength(), с другой стороны, вызов увеличит пропускную способность StringBuilder, если необходимо, посредством вызова ensureCapacityInternal() (другого очень распространенного случая, который должен был быть оптимизирован IMHO), а затем обрезает длина как delete().

В конечном итоге оба метода завершают установку count в ноль.

Ни один из вызовов не выполняет итерацию в этом случае. Оба делают ненужный вызов функции. Однако securityCapacityInternal() - очень простой частный метод, который предлагает компилятору оптимизировать его почти из-за существования, поэтому вероятность того, что setLength() немного эффективнее.

Я очень скептически отношусь к тому, что создание нового экземпляра StringBuilder может быть таким же эффективным, как просто установка count на ноль, но я полагаю, что компилятор может распознать используемый шаблон и преобразовать повторяющиеся экземпляры в повторные вызовы на setLength (0). Но в лучшем случае это будет стирка. И вы зависите от компилятора, чтобы распознать этот случай.

Резюме: setLength (0) является наиболее эффективным. Для максимальной эффективности предварительно распределите буферное пространство в StringBuilder при его создании.

Ответ 3

Метод удаления реализуется следующим образом:

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;
}

Как вы можете видеть, он не выполняет итерацию по массиву.