Java как очистить stringbuilder

Как очистить или очистить StringBuilder? [Дубликат]

Я использую StringBuilder в цикле, и каждые x итераций я хочу его очистить и начать с пустого StringBuilder , но я не вижу в документах каких-либо методов, похожих на .Net StringBuilder.Clear, только delete, который кажется слишком сложным.
Итак, каков наилучший способ очистки StringBuilder в Java?

9 ответов

  • Используйте stringBuilderObj.setLength(0) .
  • Выделите новый с помощью new StringBuilder() вместо очистки буфера

Не слишком беспокоитесь о производительности, если только это не огромная разница, так что пока я делаю это так, чтобы будущие разработчики не задавались вопросом, почему я сделал это определенным образом, я счастлив.

@ ho1: Кроме того, я думаю, что перераспределение более понятно, чем использование метода удаления с двумя индексами, но это, вероятно, вопрос предпочтений.

@Krtek: Да, но я предпочитаю, когда это возможно, делать это стандартным способом, о котором большинству разработчиков даже не придется думать, поэтому комментарии не понадобятся.

Нет, это не так дешево! Как ты можешь говорить такое? Предположим, у вас есть буфер емкостью 1000 символов. Затем вы избавляетесь от него (работа для GC) и создаете новый (работа для распределителя). Это намного быстрее, просто установить нулевую длину текста (практически без работы с процессором) и повторно использовать тот же буфер.

@Sulthan: О, поздно с этим ответом: я думал о StringBuffer.delete (idx, len). С другой стороны, выполнение setLength требует от него итерации всего буфера и обнуления каждого символа (например, kickjava.com/src/java/lang/AbstractStringBuilder.java.htm ). В зависимости от размера буфера, это может быть дорого. С другой стороны, если это не супер-производительный код, придерживайтесь того, что вам кажется наиболее понятным, и не тратьте время на микрооптимизацию.

Читайте также:  Which python version is stable

@Marcus, в ссылке, которую вы указали в качестве примера, setLength (0) не будет повторяться, как вы говорите, он будет делать это только в том случае, если новая длина больше, чем число используемых символов (не может быть с длиной 0) , С точки зрения производительности, кажется, что setLength (0) является лучшим, и это также кажется очень ясным смыслом очистки буфера.

Это не всегда возможно, например, с StringBuffer, заданным в качестве параметра для метода. setLength(0) — это путь.

@ Султан прав. Мы должны перебрать всю длину и обнулить каждый элемент, чтобы очистить StringBuilder. Вот ссылка на исходный код Java. grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/.

@ cafebabe1991 Внимательно прочитайте исходный код: if (count < newLength) , но этого никогда не произойдет, если newLength равно 0.

@Sulthan Вы определенно правы — у меня есть пара классов, которые соответственно управляют и представляют статистику, и во время вывода необходимо динамически создавать длинные пользовательские строки со многими отформатированными значениями. Повторное использование одного и того же StringBuilder вместо перераспределения при каждой распечатке статистики сократило время печати на 250 мс!

Подтверждено на Android. setLength(0) вдвое быстрее, чем new StringBuilder(200) . Использование конструктора без аргументов не имеет никакого значения, вероятно, потому что мне нужны только короткие строки для построения.

setLength также приводит к утечкам памяти, но вы обнаружите это слишком поздно. ТАК люди могут дать действительно глупые ответы время от времени. setLength не делает ничего, кроме установки длины на ноль. Остальные ассигнования все еще там. Этот ответ проистекает из javascript length = 0 для массивов, который выполняет магическую операцию, чтобы пометить массив для повторного использования, но даже там я не уверен, и не доверяю ему.

just setLegnth (0) Предложение о создании нового StringBuilder оставляет желать лучшего. Если StringBuilder становится большим (скажем, 100 МБ), нет смысла отбрасывать его в пользу его воссоздания снова и снова, когда целью очистки буфера является его повторное использование.

Это немного поздно для вечеринки, тем не менее — @momo SetLength ничего не пропускает. Он использует один и тот же буфер, который может быть, а может и не быть больше или меньше, чем вам нужно, но это ожидаемый, правильный и оптимальный для производительности режим. Память будет корректно исправлена, когда будет возвращен StringBuilder, так что это никоим образом не может быть названо утечкой. Если в какой-то момент вам нужно физически восстановить память, просто вызовите stringBuilder.trimToSize (), чтобы вернуть всю ненужную память, но это ортогонально этой проблеме.

@GerasimosR дело в том, что если вы замените большой sb на маленький . ссылка на sb все еще будет там, и я подозреваю, что старое распределение массива для всего массива будет оставаться там, неправильное использование может привести к «памяти» утечек». Если вы повторно используете sb alot и в конце сбрасываете его и устанавливаете конечную переменную, потому что вы хотите использовать ее повторно, то наибольший размер всей вашей загрузки текста (неважно, перебирая и открывая файлы для их анализа) сделает ваш sb выделяет самый большой загруженный файл. Я не уверен, что gc будет исправлять это все еще, если sb все еще в ссылке.

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

@momo Конечно — если вы используете StringBuilder для «большой» строки, вы можете ожидать, что ей будет выделен «большой» массив. Если вы установите длину в 0, вы обычно не ожидаете освобождения массива — вы ожидаете, что реализация повторно использует этот массив для следующих применений StringBuilder. Это ожидаемое поведение для (почти?) Всех смежных контейнеров, таких как ArrayList. Моя точка зрения заключалась в том, что это нельзя и не следует путать с утечкой памяти, которая является очень специфической вещью (висящая часть памяти, которая не может быть исправлена).

Т.е. если вы имеете в виду, что «если вы используете StringBuilder для большой строки, а затем используете его для небольших строк, вы будете использовать больше памяти, чем потребуется для маленьких строк», да — но в общем случае выделение памяти очень дорогие операции, поэтому большинство людей будут (должны!) делать это в любом случае, если только у них не очень ограниченный бюджет памяти. Если вы имеете в виду, что эта память каким-то образом будет вытекать и станет не востребованной после того, как пользователь закончит с ней (то есть освободит все ссылки на StringBuilder), нет — память просто «используется» в течение всего времени жизни StringBuilder.

@GerasimosR Распределение памяти большого массива действительно не востребовано из-за того, что массив все еще используется в StringBuilder, который используется для других целей. Вы говорите, что это ожидается, не выдерживает критики. Если бы вы написали библиотеку или API, в которых вы предоставили функцию reset, вы не ожидали бы дополнительных потенциальных последствий. Я говорю, что это не «правильный» подход с позиции библиотеки. Это может хорошо работать, если вы знаете, что делаете, если вы новичок, тогда все может выйти из-под контроля.

Возьмите пример, где метод объявляет и возвращает sb. Sb может использоваться и свободно переустанавливаться внутри, и вместо того, чтобы возвращать новый StringBuilder, разработчик решает очистить объявленный, который использовался для чтения файла, и вернуть все, что ему нужно, как меньший StringBuilder. У меня есть метод сброса для этого, и он не полагается на setLength из-за возможных утечек памяти, которые могут вызвать, а именно неиспользуемого пространства массива, которое не может быть освобождено из-за ссылки не на пространство массива, а на SB ссылается на устаревшее пространство массива.

Я понимаю ваше мнение. Тем не менее, это не утечка памяти, и это хорошо документированное поведение, разделяемое каждым смежным контейнером во всех трех родственных языках (C #, C ++, Java), где std :: vector, и ArrayList, StringBuilder и все остальное то, что органически растет и непрерывно распределяется, не будет перераспределяться при изменении длины. Это нельзя назвать утечкой памяти, и она хорошо документирована и прекрасно доступна в коде, предоставляя вам как size / length (), так и емкость (). Наиболее важно, что функция trimToSize () гарантирует, что это исправлено, если это то, что вы хотите

В основном есть две альтернативы, используя setLength(0) to reset StringBuilder или создавая новую на каждой итерации. Оба могут иметь плюсы и минусы в зависимости от использования.

Если вы заранее знаете ожидаемую пропускную способность StringBuilder, каждый раз создание нового должно быть таким же быстрым, как установка новой длины. Это также поможет сборщику мусора, поскольку каждый StringBuilder будет относительно недолговечным, и gc оптимизирован для этого.

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

Если вы используете setLength (0), означает ли это, что он сохраняет внутренний буфер на его текущей длине? Меня беспокоит то , что я не хочу new новый StringBuffer , потому что я ожидаю , иногда у меня будет достаточно длинные строки, и , таким образом , я начинаю с довольно большим размером буфера (4k или 32k). Так что, похоже, быстрее установить setLength (0). НО — если пространство, выделенное StringBuffer, никогда не уменьшается, я мог бы исчерпать память (это под Android, где память может быть ограничена).

@Michael: Да, внутренний буфер хранится в его текущей длине. Вы можете найти актуальную реализацию для Android на android.googlesource.com/platform/libcore/+/master/luni/src/… . Как только вы закончите добавлять символы, вы можете использовать метод trimToSize чтобы освободить ненужное пространство.

Вы написали: «Оба могут иметь плюсы и минусы в зависимости от использования». Можете ли вы привести примеры, когда лучше создавать новый StringBuilder в каждой итерации?

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

Источник

Очистка объекта StringBuilder в Java

Часто встречается ситуация, когда в процессе работы с объектом StringBuilder в Java возникает необходимость его очистить. Например, если используется цикл, в котором StringBuilder наполняется данными, и после каждого n-го повторения цикла требуется начать с пустого StringBuilder .

В Java нет прямого аналога метода Clear , который имеется в .NET для очистки StringBuilder . Вместо этого в Java есть метод delete() , который позволяет удалить подстроку из строки, хранящейся в StringBuilder . Однако использование этого метода может казаться сложным и избыточным, если нужно просто полностью очистить StringBuilder .

Наиболее простым и эффективным способом очистки StringBuilder в Java является присвоение ему нового экземпляра StringBuilder . Это можно сделать следующим образом:

StringBuilder sb = new StringBuilder(); sb.append("Hello, World!"); // Теперь sb содержит "Hello, World!" sb = new StringBuilder(); // Теперь sb пуст

Такой подход работает, потому что в Java объекты являются ссылочными типами. Когда sb присваивается новый экземпляр StringBuilder , старый экземпляр, содержащий «Hello, World!», больше не доступен и будет утилизирован сборщиком мусора.

Важно отметить, что этот подход является предпочтительным не только из-за его простоты, но и потому что он обычно будет быстрее, чем использование метода delete() . Это объясняется тем, что delete() требует времени на обновление внутреннего состояния StringBuilder , в то время как присвоение нового экземпляра StringBuilder является простой операцией.

Источник

Оцените статью