Когда мы должны изменить String на Stringbuilder? - PullRequest
3 голосов
/ 22 сентября 2011

В приложении 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 ]

6 голосов
/ 22 сентября 2011

В ваших примерах использование StringBuilder не дает никаких преимуществ, поскольку вы используете метод toString для создания неизменяемого String из вашего StringBuilder.

Вам следует скопировать содержимое StringBuilder в String только после того, как вы добавите его (или измените его каким-либо другим способом).

Проблема с Java StringBuilder заключается в том, что в ней отсутствуют некоторые методы, которые вы получаете при использовании простой строки (проверьте этот поток, например: Как реализовать StringBuilder.replace (String, String) ).

Что мы знаем, так это то, что строка использует много памяти.

На самом деле, если быть точным, String использует меньше памяти, чем StringBuilder с эквивалентным содержимым. Класс StringBuilder имеет некоторые дополнительные постоянные издержки и обычно имеет предварительно выделенный буфер для хранения большего количества данных, чем необходимо в любой данный момент (для сокращения выделений). Проблема с String s заключается в том, что они неизменны , что означает, что Java необходимо создавать новый экземпляр всякий раз, когда вам нужно изменить его содержимое.

В заключение, StringBuilder не предназначен для операций, которые вы упомянули (разбить и заменить), и в любом случае он не даст намного лучшей производительности. Метод split не может извлечь выгоду из изменчивости StringBuilder, так как он все равно создает массив неизменяемых строк в качестве своего вывода. Методом замены по-прежнему необходимо перебирать всю строку и выполнять большое копирование, если замещаемая строка не соответствует размеру искомой.

Если вам нужно много добавить , тогда выберите StringBuilder. Поскольку в нем используется «изменяемый» массив символов, добавление данных в конец будет особенно эффективным.

В этой статье сравнивается производительность нескольких методов StringBuilder и String (хотя я бы взял часть конкатенации с резервом, потому что она вообще не упоминает динамическое добавление строки и концентрируется на одиночная Join операция только).

2 голосов
/ 22 сентября 2011

Если вы часто изменяете строку, используйте StringBuilder.В противном случае, если он в любом случае неизменен, используйте String.

Чтобы ответить на ваш вопрос о том, как заменить символы, проверьте это: http://download.oracle.com/javase/tutorial/java/data/buffers.html. Операции StringBuilder - это то, что вам нужно.1008 * Вот еще одна хорошая статья о StringBuilder: http://www.yoda.arachsys.com/csharp/stringbuilder.html

1 голос
/ 22 сентября 2011

Что мы знаем, так это то, что мутация строки использует много памяти.

Это неверно. Строки не могут быть изменены . Они неизменны.

То, о чем вы на самом деле говорите, это построение строки из других строк. Это может использовать намного больше памяти, чем необходимо, но это зависит как вы строите строку.

Итак, что мы можем сделать, это использовать 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 из результата.)

1 голос
/ 22 сентября 2011

Если вам нужно много операций по изменению вашего String, тогда вы можете перейти к StringBuilder.Перейти на StringBuffer, если вы находитесь в многопоточном приложении.

0 голосов
/ 22 сентября 2011

И String, и StringBuilder используют примерно одинаковый объем памяти.Почему вы думаете, что это «много»?

Если у вас измерено (например, с jmap -histo:live), что классы [C и java.lang.String занимают большую часть памятив куче, только тогда вы должны думать дальше в этом направлении.

Возможно, есть несколько строк с одинаковым значением.Затем, поскольку String s являются неизменяемыми, вы можете intern дублировать строки.Не используйте для этого String.intern, поскольку у него плохие характеристики производительности, но у Google Guava Interner.

...