Что более эффективно 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;
}
Как вы можете видеть, он не выполняет итерацию по массиву.