Когда мы должны изменить String на Stringbuilder?
В приложении String - это часто используемый тип данных. Что мы знаем, так это то, что мутация строки использует много памяти. Так что мы можем использовать StringBuilder / StringBuffer.
Но в какой момент мы должны перейти на StringBuilder?
И что нам делать, когда мы должны разделить это или заменить символы там?
например:
//original:
String[] split = string.split("?");
//better? :
String[] split = stringBuilder.toString().split("?);
или же
//original:
String replacedString = string.replace("l","st");
//better? :
String replacedString = stringBuilder.toString().replace("l","st");
//or
StringBuilder replacedStringBuilder = new StringBuilder(stringBuilder.toString().replace("l","st);
5 ответов
Что мы знаем, так это то, что мутация строки использует много памяти.
Это неверно. Строки не могут быть изменены. Они неизменны.
То, о чем вы на самом деле говорите, это построение строки из других строк. Это может использовать намного больше памяти, чем необходимо, но это зависит от того, как вы строите строку.
Так что мы можем использовать StringBuilder/StringBuffer.
Использование StringBuilder поможет в некоторых случаях:
String res = "";
for (String s : ...) {
res = res + s;
}
(Если цикл повторяется много раз, то может оказаться целесообразным оптимизировать вышеприведенное для использования StringBuilder.)
Но при других обстоятельствах это пустая трата времени:
String res = s1 + s2 + s3 + s4 + s5;
(Оптимизировать приведенное выше для использования StringBuilder - пустая трата времени, поскольку компилятор Java автоматически преобразует выражение в код, который создает и использует StringBuilder.)
Вы должны когда-либо использовать StringBuffer вместо StringBuilder только тогда, когда строка должна быть доступна и / или обновлена более чем одним потоком; то есть когда это должно быть потокобезопасным.
Но в какой момент мы должны перейти на StringBuilder?
Простой ответ - сделать это только тогда, когда профилировщик скажет вам, что у вас проблемы с производительностью при обработке / обработке строк.
Вообще говоря, StringBuilders используются для построения строк, а не в качестве основного представления строк.
И что мы должны делать, когда мы должны разделить это или заменить символы там?
Затем вы должны пересмотреть свое решение использовать StringBuilder / StringBuffer в качестве основного представления в этой точке. И если это все еще гарантировано, вы должны выяснить, как выполнить операцию, используя выбранный вами API. (Это может повлечь за собой преобразование в строку, выполнение операции, а затем создание нового результата StringBuilder из результата.)
В ваших примерах нет никаких преимуществ в использовании StringBuilder
, так как вы используете toString
способ создать неизменный String
из вашего StringBuilder
,
Вы должны только скопировать содержимое StringBuilder
в String
после того, как вы закончите добавление (или изменение каким-либо другим способом).
Проблема с Java StringBuilder
является то, что ему не хватает некоторых методов, которые вы получаете при использовании простой строки (проверьте этот поток, например: Как реализовать StringBuilder.replace (String, String)).
Что мы знаем, так это то, что строка использует много памяти.
На самом деле, если быть точным, String
использует меньше памяти, чем StringBuilder
с эквивалентным содержанием. StringBuilder
Класс имеет некоторые дополнительные постоянные издержки и обычно имеет предварительно выделенный буфер для хранения большего количества данных, чем необходимо в любой данный момент (чтобы уменьшить выделения). Вопрос с String
Суть в том, что они неизменны, что означает, что Java должна создавать новый экземпляр всякий раз, когда вам нужно изменить его содержимое.
Заключить, StringBuilder
не предназначен для операций, которые вы упомянули (разделить и заменить), и в любом случае он не даст намного лучшей производительности. split
метод не может извлечь выгоду из StringBuilder
изменчивость, так как он создает массив неизменяемых строк в любом случае. Методом замены по-прежнему необходимо перебирать всю строку и выполнять многократное копирование, если замещаемая строка не соответствует размеру искомой.
Если вам нужно сделать много дополнений, а затем пойти на StringBuilder
, Поскольку он использует "изменяемый" массив символов внутри, добавление данных в конец будет особенно эффективным.
В этой статье сравнивается производительность нескольких StringBuilder
а также String
методы (хотя я бы взял часть конкатенации с резервом, потому что она не упоминает динамическое добавление строки вообще и концентрируется на одном Join
только операция).
Если вы часто изменяете строку, перейдите с StringBuilder
, В противном случае, если это так или иначе является неизменным, пойти с String
,
Чтобы ответить на ваш вопрос о том, как заменить символы, проверьте это: http://download.oracle.com/javase/tutorial/java/data/buffers.html. Операции StringBuilder - это то, что вы хотите.
Вот еще одна хорошая статья о StringBuilder
: http://www.yoda.arachsys.com/csharp/stringbuilder.html
Если вам нужно много операций по изменению вашего String
тогда вы можете пойти на StringBuilder
, Пойти на StringBuffer
если вы находитесь в многопоточном приложении.
Оба String
и StringBuilder
использовать примерно столько же памяти. Почему вы думаете, что это "много"?
Если вы измерили (например, с jmap -histo:live
) что классы [C
а также java.lang.String
занять большую часть памяти в куче, только тогда вы должны думать дальше в этом направлении.
Может быть, есть несколько строк с одинаковым значением. Тогда, так как String
s являются неизменными, вы могли бы интернировать дубликаты строк. Не использовать String.intern
для него, так как он имеет плохие характеристики производительности, но Google Guava Interner
,