Main > Java | Java labs > String vs StringBuilder

String vs StringBuilder

14.04.2012 0 comments » Views: 4,494

Сегодня я протестирую скорость добавления строки, при использовании двух классов: класса String и класса StringBuilder.

Сразу начну с примера:

Результат работы:

Как видите String работает во много раз медленнее чем StringBuilder. Как же так? Давайте разбираться!

Что происходит в программе?

Мы создаем длинную строку из 100.000 букв, по очереди добавляя их к 1 длинной строке. Соответственно засекаем время до начала и после окончания работы. И выводим разницу во времени.

Почему медленно работает String?

Дело в том, что объекты класса String (его экземпляры), являются неизменяемыми (на англ. immutable). Это означает, что эти объекты нельзя изменить, при их изменении они пересоздаются заново. Как же это реализовано, давайте посмотрим исходник класса String:

Как видим, класс объявлен final = это означает, что мы не можем отнаследовать этот класс, но это не главное. Главное, что массив char-ов который используется как хранилище (storage) объявлен так же как final, а это значит, что этот массив, после внесения в него данных уже нельзя поменять! Вот и вся хитрость.

Вернемся к нашей программе, что же происходит при добавлении буквы? Создается новая строка, туда копируется старая строка + новая буква. Т.е. по сути мы 100.000 раз создаем новую строку и копируем туда прошлый результат. Когда строка состоит из пары букв, это не особо критично, на представьте что нужно копировать строку из 99.999 символов,  только для добавления одного символа. Это очень накладно, поэтому и медленно.

Почему быстро работает StringBuilder?

Потому что, в отличии от String, объекты StringBuilder являются изменяемыми (mutable), это значит, что при добавлении буквы, массив представляющий хранилище не копируется заново. Давайте так же глянем как он реализован:

Как видим, в этом случае, хранилище не объявлено как final. А это значит, что при каждом добавлении, не происходит копирование всей старой строки в новую переменную. Но можно ли утверждать это? На самом деле нет! Давайте взглянем на метод добавления:

Как видите, тут присутствует вызов такого метода: ensureCapacityInternal. Именно он и помогает оптимизировать работу всего класса. А работает это так:

  1. Создается например заранее готовый массив в 100 символов
  2. Пока вы добавляете поочередно 100 символов, массив не изменяется
  3. Как только вы станете добавлять 101 символ, массив будет создан заново, но уже размером в 100+100 символов, и в него будет скопирован старый массив, именно за эту проверку и увеличение размера отвечает ensureCapacityInternal

Обратите внимание, что размер именно в 100 символов, я выбрал просто для примера. Точное значение можно посмотреть в конструкторе класса StringBuilder, в моем случае это был массив из 16 символов.

Итак копирование все же происходит, но класс хитрит и выделяет размерность массива, как бы наперед. Как видите особых сложностей нет.

Как это работает думаю понятно.

Почему String неизменяемый (immutable)?

Это сделано, в моем понимании, для использования кеширования строк. Компилятор, чтобы оптимизировать работу со строками, одинаковые строки, хранит в одной и той же ячейке памяти (не буду вдаваться сейчас в подробности, возможно позже напишу отдельный пост), сделать он может это только с константами, поэтому String пришлось сделать final. Отсюда и растут ноги.

Когда использовать String, а когда StringBuilder?

Думаю это очевидно: String используем всегда, когда не требуется частых изменений строк. StringBuilder - как и следует из названия, когда нужно "строить" строки, т.е. менять часто их значения. Это может быть добавление, вставка или удаление символа - посмотрите методы StringBuilder'а и поймете где его ещё лучше использовать.

Что еще интересного в этом примере?

Я создал класс Timer, с помощью которого засекаю время. Возможно он Вам пригодится, если вы захотите измерить скорость работы Вашей программы или какого-то метода.

 

Вопросы для собеседования:

  1. В чем отличие работы со строками с помощью классов String и StringBuilder?
  2. Когда использовать String, а когда StringBuilder

Ответы:

  1. Объекты класса String является неизменяемым(immutable), а объекты класса StringBuilder являются изменяемыми (mutable)
  2. String - когда нет или мало изменений со строкой хранящейся в экземпляре класса. StringBuilder - когда надо делать изменения со строкой хранящейся в экземпляре класса.

Author: | Rating: 4/5 | Tags: , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

Allowed HTML-tags: <a>, <code>, <i>, <em>, <strong>, <b>, <u>, <strike>