StringBuilder — Java: Массивы
Генерация строк в циклах — задача, часто возникающая на практике. Типичный пример — метод, помогающий генерировать HTML-списки. Он принимает на вход массив элементов и возвращает HTML-список из них:
Как можно решить эту задачу «в лоб»:
- Создать переменную result и записать в нее
-
.
- Пройтись циклом по элементам коллекции и дописать в результирующую строку очередной элемент
- .
- Добавить в конце
и вернуть result из функции.
Такой способ вполне рабочий, но для большинства языков программирования максимально неэффективный. Дело в том, что конкатенация порождает новую строчку вместо старой, — и подобная ситуация повторяется на каждой итерации. Причем строка становится все больше и больше. Копирование строк приводит к серьезному расходу памяти и влияет на производительность.
Правильный способ для динамической сборки строк в Java — использование класса StringBuilder . Он позволяет собирать строку по кусочкам без лишнего копирования. Перепишем наш пример:
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
StringBuilder в Java
Программы Java используют класс StringBuilder для добавления строк. Добавление строк становится все более сложным процессом по мере того, как строки становятся длиннее.
Требуется все больше и больше памяти. Программы тормозят.
Решение. Класс StringBuilder в Java – решение этой проблемы, он просто повторно использует единственный буфер. Ускоряет добавления, вставки.
Пример далее импортирует java.lang.StringBuilder. Мы создаем StringBuilder. Зацикливаем и добавляем к нему пять строк и конвертируем данные в объект String. Затем отображаем полученную строку в консоли с помощью метода System.out.println.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < // Create a new StringBuilder. StringBuilder builder = new StringBuilder(); // Loop and append values. for (int i = 0; i < 5; i++) < builder.append("abc "); >// Convert to string. String result = builder.toString(); // Print result. System.out.println(result); > > Output abc abc abc abc abc
Часто мы используем StringBuilders в циклах. Здесь у нас часто неизвестное количество итераций. А StringBuilder оптимизирует случаи, когда происходит много вызовов append().
Следовательно использование StringBuilder в цикле может предотвратить возникновение проблемы с производительностью генерации.
StringBuilder может добавлять данные многих типов. Мы не ограничены строками. С помощью метода append () мы можем добавлять целые числа, двойные числа, символы — любой числовой тип.
В этом примере мы вызываем append() для результата предыдущего вызова append() и он возвращает исходный StringBuilder.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < int value1 = 300; double value2 = 3.14; short value3 = 5; char value4 = 'A'; // Create StringBuilder and add four values to it. StringBuilder builder = new StringBuilder(); builder.append(value1).append("\n"); builder.append(value2).append("\n"); builder.append(value3).append("\n"); builder.append(value4); // Display results. String result = builder.toString(); System.out.println(result); >> Output 300 3.14 5 A
StringBuilder имеет изменяемый буфер. Таким образом, мы можем быстро добавлять или вставлять данные. Он получает два аргумента: индекс и значение, которое мы хотим вставить.
Индекс: это первый аргумент. Чтобы вставить после второго символа, используйте значение 2. А для вставки в начале используйте ноль.
Строка: мы передаем строку (или другое значение) в качестве второго аргумента. Это данные, которые помещаются в стрингбилдер.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < // Initialize StringBuilder with this value. StringBuilder builder = new StringBuilder("abc"); // Insert this substring at position 2. builder.insert(2, "xyz"); System.out.println(builder); >> Output abxyzc
Мы используем метод indexOf для поиска подстроки в данных. Если подстрока найдена, первый индекс, в котором она встречается, возвращается как int.
Не найдено: если подходящая подстрока не найдена, возвращается отрицательное значение. Мы должны часто проверять -1 при использовании indexOf.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < StringBuilder builder = new StringBuilder("abc"); // Try to find this substring. int result = builder.indexOf("bc"); System.out.println(result); // This substring does not exist. int result2 = builder.indexOf("de"); System.out.println(result2); >> Output 1 -1
Удаление. Мы передаем ему два аргумента типа int. Первый аргумент — это начальный индекс, с которого должно начинаться удаление. И второй аргумент — это конечный индекс.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < StringBuilder builder = new StringBuilder("carrot"); // Delete characters from index 2 to index 5. builder.delete(2, 5); System.out.println(builder); >> Output cat
Замена. Этот метод принимает два индекса и заменяет символы в этом диапазоне указанной строкой. Replace в StringBuilder работает иначе, чем replace() в Strings.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < // Create new StringBuilder. StringBuilder b = new StringBuilder("abc"); // Replace second character with "xyz". b.replace(1, 2, "xyz"); System.out.println(b); >> Output axyzc
Объединение. Мы можем добавить один StringBuilder к другому. Мы просто вызываем append() и передаем второй StringBuilder в качестве аргумента.
public class Program < public static void main(String[] args) < StringBuilder builder = new StringBuilder("cat"); StringBuilder builder2 = new StringBuilder("dog"); // Combine two StringBuilders. builder.append(builder2); System.out.println(builder); >> Output catdog
Подстрока или Substring в Java. Этот метод находится в классе AbstractStringBuilder. Он предоставляет полезную возможность извлекать диапазон символов в новую строку.
Аргументы: первый аргумент — это начальный индекс желаемой подстроки. Второй аргумент — это последний индекс (а не количество символов).
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < StringBuilder builder = new StringBuilder(); builder.append("Forest"); // Get substring after the first two characters. String omitFirstTwo = builder.substring(2); System.out.println(omitFirstTwo); // Get only the first two characters in a substring. String firstTwo = builder.substring(0, 2); System.out.println(firstTwo); >> Output rest Fo
Перебор символов. Цикл for может перебирать символы. Мы обращаемся к методу length(), чтобы получить размер StringBuilder, а затем используем charAt() для доступа к символам.
Длина: этот метод возвращает количество символов в StringBuilder. Самый высокий индекс — это количество символов минус один.
CharAt: обращается к символу в StringBuilder. Мы можем использовать его где угодно, а не только в цикле for.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < StringBuilder builder = new StringBuilder("magic"); // Loop over the characters in this StringBuilder. for (int i = 0; i < builder.length(); i++) < System.out.println(builder.charAt(i)); >> > Output m a g i c
SetLength. Мы можем изменить длину StringBuilder с помощью setLength. Это часто бывает полезно, когда мы хотим сократить или уменьшить количество символов в объекте.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < StringBuilder builder = new StringBuilder("carrot"); // Use setLength to remove characters from the end. builder.setLength(3); System.out.println(builder); >> Output car
Вместимость. Внутренне StringBuilder изменяется по мере увеличения количества символов. Это медленно. Благодаря большей емкости, установленной в конструкторе, мы избегаем этих изменений размеров.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < // Use a 100-char capacity. StringBuilder temp = new StringBuilder(100); // Add 100 characters to the StringBuilder. // . Theoretically this is faster. for (int i = 0; i < 25; i++) < temp.append("1234"); >System.out.println(temp.length()); > > Output 100
Reverse. В этом примере выполняется обратное преобразование. Он вызывает метод reverse(). Обратить строку легко — сначала мы должны поместить ее содержимое в StringBuilder.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < // A StringBuilder can be reversed. StringBuilder builder = new StringBuilder(); builder.append("abc"); builder.reverse(); System.out.println(builder); >> Output cba
StringBuilder намного быстрее делает добавление, чем String. Для добавления String требуется значительное время(251 мс), а для добавления StringBuilder требуется менее 1 мс.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < long t1 = System.currentTimeMillis(); // Version 1: add to string. String value = ""; for (int i = 0; i < 10000; i++) < value += Integer.toString(i) + ' '; >long t2 = System.currentTimeMillis(); // Version 2: append to StringBuilder. StringBuilder builder = new StringBuilder(); for (int i = 0; i < 10000; i++) < builder.append(i).append(' '); >long t3 = System.currentTimeMillis(); // . Lengths are equal. System.out.println(value.length()); System.out.println(builder.length()); // . Times. System.out.println(t2 - t1); System.out.println(t3 - t2); > > Results 48890 48890 251 ms, String + operator (20000 adds) 0 ms, StringBuilder append (20000 calls)
Производительность емкости. Здесь мы возвращаемся к емкости. В этом тесте размер первого StringBuilder увеличивается до миллиона символов без установленной емкости.
И еще: второй StringBuilder тем временем использует точную емкость 1000000.
Результат: точная емкость позволяет второму StringBuilder почти в два раза быстрее выполнять свою задачу.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < long t1 = System.currentTimeMillis(); // Version 1: does not use capacity. StringBuilder builder = new StringBuilder(); for (int i = 0; i < 1000000; i++) < builder.append(' '); >long t2 = System.currentTimeMillis(); // Version 2: uses exact capacity. StringBuilder builder2 = new StringBuilder(1000000); for (int i = 0; i < 1000000; i++) < builder2.append(' '); >long t3 = System.currentTimeMillis(); // . Times. System.out.println(t2 - t1); System.out.println(t3 - t2); > > Results 10 ms, no capacity 6 ms, exact capacity
Добавление строки вместо символа. Вот еще один тест. Он сравнивает вызов append() с односимвольным строковым литералом и char. Аргумент String работает медленнее.
Когда это возможно: быстрее использовать аргумент char для append(), чем аргумент String. Я обнаружил, что это помогает многим программам.
import java.lang.StringBuilder; public class Program < public static void main(String[] args) < long t1 = System.currentTimeMillis(); // Version 1: appends one-char strings. StringBuilder builder = new StringBuilder(); for (int i = 0; i < 1000000; i++) < builder.append("X"); >long t2 = System.currentTimeMillis(); // Version 2: appends chars directly. StringBuilder builder2 = new StringBuilder(); for (int i = 0; i < 1000000; i++) < builder2.append('X'); >long t3 = System.currentTimeMillis(); // . Times. System.out.println(t2 - t1); System.out.println(t3 - t2); > > Results 15 ms, append() String argument 7 ms, append() char argument
Массивы символов. Мы можем использовать массив символов вместо StringBuilder для создания строк. В моих тестах это быстрее, но размер массивов нельзя изменить, поэтому он менее гибкий.
StringBuffer. Это более старая версия StringBuilder. Эти два класса почти одинаковы, за исключением того, что StringBuffer является потокобезопасным и несколько медленнее.
StringBuilder лучше всего использовать его в циклах. В этих случаях происходит много итераций, и вызывается много вызовов добавления. Скорость. Основная цель — повысить производительность. В простых ситуациях String может быть быстрее.
Средняя оценка 4.7 / 5. Количество голосов: 22
Спасибо, помогите другим — напишите комментарий, добавьте информации к статье.
Или поделись статьей
Видим, что вы не нашли ответ на свой вопрос.
Помогите улучшить статью.
Напишите комментарий, что можно добавить к статье, какой информации не хватает.
String, StringBuilder и StringBuffer: понимаете ли вы разницу?
Все разработчики имеют дело со словами и фразами в некоторых частях кода. String — это тип данных, используемый в программировании для представления текста.
В Java есть три класса с именами String , StringBuilder и StringBuffer , где содержатся методы, написанные для операций над строками. Эти классы включены в пакет lang и импортируются в Java-код автоматически.
Здесь я расскажу подробнее об этих классах, а также о том, как и когда их использовать, чтобы облегчить себе работу со строками.
String
Строки в Java иммутабельны (не могут быть изменены). При изменении объекта String в Java каждый раз создается совершенно новый объект. В Java существует два способа объявить объект String, как это показано в примере ниже:
class StrEx1 public static void main(String[] args) String s1 = "This is a String"; // Объявлено с использованием строкового литерала
String s2 = new String("This is another String"); // Объявлено с использованием оператора new
>
>
Разница между этими двумя способами в том, что при использовании оператора new в памяти кучи каждый раз будет создаваться новый объект String. При использовании литерала объекта, если такой объект уже существует в куче, новый объект не появится, а ссылочная переменная будет указывать на существующий объект. При использовании строкового литерала объект String в Java сохраняется в так называемом пуле строк (String Pool). Он расположен внутри памяти кучи, что помогает Java Runtime сэкономить много места, даже если для создания объекта String при этом требуется больше времени. Так что, если вы хотите каждый раз создавать новый объект String, вам следует воспользоваться оператором new, а если вы хотите сберечь память кучи, тогда используйте строковый литерал.
При использовании оператора new, если в пуле строк такого объекта не существует, то сначала он будет создан в пуле строк, а затем уже и в памяти кучи. Ссылка на созданный строковый объект в таком случае всегда указывает на объект области кучи. Но если объект String уже существует в пуле строк, то объект будет создан только в памяти кучи. Такой вопрос нередко задают на собеседованиях по Java.
Класс String также предоставляет доступ ко многим полезным методам для различных операций над строками. Вот некоторые из этих методов: substring() , charat() , length() , equals() , concat() , replace() , trim() , split() , toUpperCase() и toLowerCase() . Эти методы можно применять как по отдельности, так и в сочетании с другими методами класса String, чтобы манипулировать строками так, как нам того захочется.
class StrEx2 public static void main(String args[]) String s1 = "Hello World";
String s2 = s1.substring(0,5).concat(" r2d2").toUpperCase();
System.out.println(s2); // Результат: HELLO R2D2
>
>
Здесь значение переменной s1 не изменяется.
StringBuilder
Класс StringBuilder представляет собой альтернативу классу String, поскольку создает мутабельный (изменяемый) набор символов. Класс StringBuilder, как и класс String, содержит набор методов для управления строковыми объектами.
class SbdEx1 public static void main(String args[]) StringBuilder sbd = new StringBuilder("Hello World");
String s = sbd.replace(5,11,"").append(" r2d2").toString();
System.out.println(sbd); // Результат: Hello r2d2
System.out.println(s.toUpperCase()); //Результат: HELLO R2D2
>
>
Классы StringBuilder и StringBuffer предоставляют важные методы, которых не предоставляет класс String, такие как insert() , delete() и reverse() . Если вы много раз совершаете какие-либо действия над строками в коде, вам следует использовать StringBuilder или StringBuffer, потому что они намного быстрее и потребляют меньше памяти, чем String. Например, если вы используете конкатенацию строк в цикле, то лучше применять StringBuilder.
class SbdEx2 public static void main(String args[]) StringBuilder sbd = new StringBuilder("0");
for (int i = 1; i < 100; i++) sbd.append(", "+i);
>
>
>
Класс StringBuilder не обеспечивает синхронизацию: экземпляры класса StringBuilder не могут совместно использоваться несколькими потоками. Для операций со строками в среде, не являющейся многопоточной, стоит использовать StringBuilder, потому что он быстрее, чем StringBuffer.
StringBuffer
Как и класс StringBuilder, класс StringBuffer также создает изменяемый строковый объект. И StringBuffer содержит те же методы, что и StringBuilder. Таким образом, разница между ними в том, что класс StringBuffer — потокобезопасный и синхронизированный: экземпляры класса StringBuffer могут совместно использоваться несколькими потоками. Для операций со строками в многопоточных средах стоит использовать StringBuffer.
class Test extends Thread <
StringBuffer sbr;
public Test() sbr = new StringBuffer();
>
public String hello() sbr.append("Hello World");
return(sbr.toString());
>
>
public class SbrEx <
public static void main(String args[]) Test thread1 = new Test();
thread1.start();
Test thread2 = new Test();
thread2.start();
System.out.println(thread1.hello());
System.out.println(thread2.hello());
>
>
Здесь несколько потоков обращаются к методу hello() , поэтому для обеспечения потокобезопасности необходимо применить StringBuffer.
Надеюсь, что вы все теперь разобрались со String, StringBuilder и StringBuffer. Спасибо, что прочитали!
- Java. Вложенные классы
- Портируем решатель судоку с Java на WebAssembly
- Основы программирования UDP-сокетов на Java
Как работает stringbuilder java
PHANTOM Уровень 41 EXPERT 15 февраля, 16:18 В самом начале изучения Java тоже придерживался того что нужно решить задачу и потом двигаться дальше(мой перфекционизм).. но.. через какое то время я понял что это неэффективно. Потеешь над задачей 3-4 часа, решишь — хорошо, есть мотивация но мозг уже переутомился и к усвоению новой информации не готов, не решишь — нет мотивации, и также не готов к усвоению новой информации. И за этого тебе нужно делать перерыв, возможно до следующего дня. Одним словом топчишься на одном месте. Поэтому конечно, сначала максимум теории, изучить тему вдоль и поперек, потом можно приступать к решению задачи закрепляя практикой. Виктор, благодарю за мотивацию.
Denis Gritsay Уровень 23
28 октября 2023
решаю параллельно задачки на codewars , там много задач на string, надо запомнить этот стринг балдер.
Wells_D Уровень 13
1 октября 2023
а вот статья о HashMap была очень понятной, и в плане объяснения темы, и для чего это может использоваться, даже без написания практического кода)
Wells_D Уровень 13
1 октября 2023
очевидно полезно) чем дальше , тем не понятней для чего используется, в каких конкретных задачах, а примеры( и практические задачи все более бессмысленные и для чего оно нужно. по началу как то было понятно для чего делается (практическая задача )и какую функцию она выполняет, а сейчас просто перебор текста непонятно с какой целью, интерес пропадает напрочь, практические задачи просто какая то дичь и чепуха, написание каких либо нормальных программ ( с человеческим интерфейсом , хотя бы простой калькулятор) несло бы куда больше пользы, чем поменять местами слова в пословице, для чего не ясно) такое ощущение будто занимаешься переливанием воды из одного стакана в другой) результат работы кода невероятно интересный и полезный — Учиться, учиться и еще раз учиться! Под лежачий камень вода не течет Учиться, учиться, учиться! Учиться что бы создавать такую дичь)
