Как переназначить значение StringBuffer? - PullRequest
14 голосов
/ 07 апреля 2010

Как мы можем повторно присвоить значение переменной StringBuffer или StringBuilder?

StringBuffer sb=new StringBuffer("teststr");

Теперь мне нужно изменить значение sb на "testString" без очистки содержимого. Я смотрю на метод, который может выполнить это назначение напрямую, без использования отдельного выделения памяти. Я думаю, что мы можем сделать это только после очистки содержимого.

Ответы [ 8 ]

22 голосов
/ 07 апреля 2010
sb.setLength(0);
sb.append("testString");
16 голосов
/ 12 апреля 2010

Прежде всего следует отметить, что StringBuilder обычно предпочтительнее StringBuffer. От StringBuffer собственного API :

Начиная с выпуска JDK 5, этот класс был дополнен эквивалентным классом, предназначенным для использования одним потоком, StringBuilder. Класс StringBuilder обычно следует использовать вместо этого, поскольку он поддерживает все те же операции, но он быстрее, поскольку не выполняет синхронизацию.

Тем не менее, я буду придерживаться StringBuffer для остальной части ответа, потому что это то, что вы спрашиваете; все, что делает StringBuffer, StringBuilder также ... кроме синхронизации, которая обычно не нужна. Поэтому, если вы не используете буфер в нескольких потоках, переключение на StringBuilder является простой задачей.


Вопрос

StringBuffer sb = new StringBuffer("teststr");

«Теперь мне нужно изменить значение sb на "testString" без очистки содержимого» * ​​1027 *

То есть вы хотите, чтобы sb содержал String значение "testString" в своем буфере? Есть много способов сделать это, и я перечислю некоторые из них, чтобы проиллюстрировать, как использовать API.


Оптимальное решение: минимальное редактирование: от "teststr" до "testString". Это невозможно сделать быстрее, чем это.

StringBuffer sb = new StringBuffer("teststr");
sb.setCharAt(4, 'S');
sb.append("ing");
assert sb.toString().equals("testString");

Это без необходимости перезаписывает "tr" с "tr".

StringBuffer sb = new StringBuffer("teststr");
sb.replace(4, sb.length(), "String");
assert sb.toString().equals("testString");

Это включает в себя сдвиги из-за deleteCharAt и insert.

StringBuffer sb = new StringBuffer("teststr");
sb.deleteCharAt(4);
sb.insert(4, 'S');
sb.append("ing");
assert sb.toString().equals("testString");

Теперь все по-другому: он не знает, что у него есть "teststr", который нужно отредактировать до "testString"; предполагается, что StringBuffer содержит хотя бы одно вхождение "str" где-то, и его необходимо заменить на "String".

StringBuffer sb = new StringBuffer("strtest");
int idx = sb.indexOf("str");
sb.replace(idx, idx + 3, "String");
assert sb.toString().equals("Stringtest");

Предположим теперь, что вы хотите заменить ALL вхождений "str" и заменить его "String". A StringBuffer не имеет этой встроенной функции. Вы можете попытаться сделать это самостоятельно наиболее эффективным из возможных способов, либо на месте (возможно, с помощью 2-проходного алгоритма), либо с помощью второго StringBuffer и т. Д.

Но вместо этого я буду использовать replace(CharSequence, CharSequence) из String. В большинстве случаев это будет более чем достаточно, и, безусловно, намного понятнее и проще в обслуживании. Она линейна по длине входной строки, поэтому она асимптотически оптимальна.

String before = "str1str2str3";
String after = before.replace("str", "String");
assert after.equals("String1String2String3");

Обсуждение

«Я ищу способ назначить значение позже, используя предыдущую ячейку памяти»

Точное местоположение памяти не должно беспокоить вас; фактически, StringBuilder и StringBuffer будут перераспределять свой внутренний буфер в разные области памяти при необходимости. Единственный способ предотвратить это - ensureCapacity (или установить его через конструктор), чтобы его внутренний буфер всегда был достаточно большим и его никогда не понадобилось перераспределять.

Однако, даже если StringBuffer перераспределяет свой внутренний буфер время от времени, это не должно быть проблемой в большинстве случаев. Большинство динамически растущих структур данных (ArrayList, HashMap и т. Д.) Выполняют их таким образом, чтобы сохранить алгоритмически оптимальные операции, используя преимущества амортизации затрат. Я не буду проходить амортизированный анализ здесь, но если вы не используете системы реального времени и т. Д., Это не должно быть проблемой для большинства приложений.

Очевидно, что я не знаю специфики вашей потребности, но есть страх преждевременной оптимизации, так как вы, кажется, беспокоитесь о вещах, о которых большинству людей не приходится беспокоиться.

8 голосов
/ 07 апреля 2010

Что вы имеете в виду под «переназначением»?Вы можете очистить содержимое с помощью setLength(), а затем начать добавление нового содержимого, если вы это имеете в виду.

Редактировать : для изменения частей содержимого,Вы можете использовать replace().

Как правило, на этот вопрос легко ответить, посмотрев документацию по API рассматриваемых классов.

3 голосов
/ 07 апреля 2010

Вы можете использовать StringBuilder вместо StringBuffer, что обычно делают люди, если могут (StringBuilder не синхронизирован, поэтому он быстрее, но не безопасен для потоков). Если вам нужно инициализировать содержимое одного с другим, используйте метод toString(), чтобы получить строковое представление. Чтобы переработать существующий StringBuilder или StringBuffer, просто позвоните setLength(0).

Редактировать
Вы можете перезаписать диапазон элементов с помощью функции replace(). Чтобы изменить все значение на newval, вы должны использовать buffer.replace(0,buffer.length(),newval). Смотри также:

2 голосов
/ 07 апреля 2010

Возможно, вы ищете метод replace () в StringBuffer:

StringBuffer sb=new StringBuffer("teststr");
sb.replace(0, sb.length() - 1, "newstr");

Внутренне он удаляет исходную строку, затем вставляет новую строку, но может избавить вас от этого шага:

StringBuffer sb=new StringBuffer("teststr");
sb.delete(0, sb.length() - 1);
sb.append("newstr");

Использование setLength (0) переназначает переменную StringBuffer нулевой длины для переменной, что, я думаю, не то, что вы хотите:

StringBuffer sb=new StringBuffer("teststr");
// Reassign sb to a new, empty StringBuffer
sb.setLength(0);
sb.append("newstr");
1 голос
/ 15 апреля 2010

Действительно, я думаю, replace() - лучший способ.Я проверил исходный код Java.Он действительно перезаписывает старые символы.

Вот исходный код функции replace ():

public AbstractStringBuffer replace(int start, int end, String str)
  {
    if (start < 0 || start > count || start > end)
      throw new StringIndexOutOfBoundsException(start);

    int len = str.count;
    // Calculate the difference in 'count' after the replace.
    int delta = len - (end > count ? count : end) + start;
    ensureCapacity_unsynchronized(count + delta);

    if (delta != 0 && end < count)
      VMSystem.arraycopy(value, end, value, end + delta, count - end);

    str.getChars(0, len, value, start);
    count += delta;
    return this;
  }
0 голосов
/ 04 февраля 2016

Изменение всего значения StringBuffer:

  StringBuffer sb = new StringBuffer("word");
  sb.setLength(0); // setting its length to 0 for making the object empty
  sb.append("text");

Таким образом вы можете изменить все значение StringBuffer.

0 голосов
/ 07 апреля 2010

Вы можете конвертировать в / из строки следующим образом:

 StringBuffer buf = new StringBuffer();
 buf.append("s1");
 buf.append("s2");

 StringBuilder sb = new StringBuilder(buf.toString());
 // Now sb, contains "s1s2" and you can further append to it
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...