Ранее рассмотренный класс строк String позволяет
создавать и обрабатывать строки в виде неизменяемого объекта. То есть, при
обработке строк часто создавался новый объект класса String с новой
(обработанной) строкой. С точки зрения производительности такой подход является
довольно ресурсоемким. Поэтому в Java были введены еще
два класса работы со строками StringBuffer и StringBuilder, которые позволяют
изменять строку без создания нового объекта, а значит без ущерба для
производительности.
Эти классы похожи, практически двойники,
они имеют одинаковые конструкторы, одни и те же методы, которые одинаково
используются. Единственное их различие состоит в том, что класс StringBuffer
синхронизированный и потокобезопасный. То есть класс StringBuffer удобнее
использовать в многопоточных приложениях, где объект данного класса может
меняться в различных потоках. Если же речь о многопоточных приложениях не идет,
то лучше использовать класс StringBuilder, который не потокобезопасный, но при
этом работает быстрее, чем StringBuffer в однопоточных приложениях.
Класс StringBuffer имеет четыре таких конструктора:
-
StringBuffer()
-
StringBuffer(int
capacity)
-
StringBuffer(String
str)
-
StringBuffer(CharSequence
chars)
Ничего страшного, если вы пока не
знакомы с понятием конструктора в ООП. Сейчас на конкретных примерах вы легко
поймете как они используются при создании соответствующих объектов.
Аналогичные конструкторы имеет и класс
StringBuilder:
-
StringBuilder()
-
StringBuilder(int
capacity)
-
StringBuilder(String
str)
-
StringBuilder(CharSequence
chars)
Далее мы будем рассматривать работу этих
классов на примере класса StringBuffer (StringBuilder работает
аналогично).
Как вы понимаете классы StringBuffer и StringBuilder
не могут заранее знать сколько памяти им понадобиться при работе со строками.
Поэтому они заранее резервируют некую дополнительную область памяти «на всякий
случай», например, если строка при обработке будет увеличиваться в размерах.
Если же зарезервированного размера памяти оказывается недостаточно, то
происходит выделение новой области памяти (также с некоторым запасом) и туда
копируется текущая строка. Конечно, желательно избегать такой ситуации и далее
мы увидим как это можно сделать.
Итак, конструктор без параметров
резервирует в памяти место всего лишь для 16 символов. Если мы хотим, чтобы
количество символов было иным, то можем использовать второй конструктор, где в
качестве параметра указывается количество резервируемых символов.
Третий и четвертый конструкторы обоих
классов принимают строку и набор символов, при этом резервируя память еще для
дополнительных 16 символов.
Чтобы нам узнать для скольки символов
зарезервирована память, нужно вызвать метод capacity(). А с помощью метода
ensureCapacity() можно изменять минимальную емкость буфера символов:
String str = "Java";
StringBuffer strBuffer = new StringBuffer(str);
System.out.println("Емкость: " + strBuffer.capacity()); // 20
strBuffer.ensureCapacity(32);
System.out.println("Емкость: " + strBuffer.capacity()); // 42
System.out.println("Длина: " + strBuffer.length()); // 4
Так как в самом начале StringBuffer
инициализируется строкой "Java", то его емкость составляет 4 + 16 =
20 символов. Затем мы увеличиваем емкость буфера с помощью вызова
strBuffer.ensureCapacity(32) повышаем минимальную емкость буфера до 32
символов. Однако финальная емкость может отличаться в большую сторону. Так, в
данном случае я получаю емкость не 32 и не 32 + 4 = 36, а 42 символа. Дело в
том, что в целях повышения эффективности Java может дополнительно выделять
память.
Но в любом случае вне зависимости от
емкости длина строки, которую можно получить с помощью метода length(), в
StringBuffer остается прежней - 4 символа (так как в "Java" 4
символа).
Чтобы получить строку, которая хранится
в StringBuffer, мы можем использовать стандартный метод toString():
Получение и изменение символов
Метод charAt()
получает, а метод setCharAt() изменяет символ по определенному индексу:
StringBuffer strBuffer = new StringBuffer("Java");
char c = strBuffer.charAt(0); // J
System.out.println(c);
strBuffer.setCharAt(0, 'c');
System.out.println(strBuffer.toString()); // cava
Метод getChars()
позволяет извлечь набор символов между определенными индексами:
StringBuffer strBuffer = new StringBuffer("world");
int startIndex = 1;
int endIndex = 4;
char[] buffer = new char[endIndex-startIndex];
strBuffer.getChars(startIndex, endIndex, buffer, 0);
System.out.println(buffer); // orl
Добавление в строку
Метод append() добавляет
подстроку в конец строки класса StringBuffer:
Метод insert()
добавляет строку или символ по определенному индексу:
StringBuffer strBuffer = new StringBuffer("word");
strBuffer.insert(3, 'l');
System.out.println(strBuffer.toString()); //world
strBuffer.insert(0, "s");
System.out.println(strBuffer.toString()); //sworld
Удаление символов
Метод delete()
удаляет все символы с определенного индекса о определенной позиции, а метод
deleteCharAt() удаляет один символ по определенному индексу:
StringBuffer strBuffer = new StringBuffer("assembler");
strBuffer.delete(0,2);
System.out.println(strBuffer.toString()); //sembler
strBuffer.deleteCharAt(6);
System.out.println(strBuffer.toString()); //semble
Обрезка строки
Метод
substring() обрезает строку с определенного индекса до конца, либо до
определенного индекса:
StringBuffer strBuffer = new StringBuffer("hello java!");
String str1 = strBuffer.substring(6); // обрезка строки с 6 символа до конца
System.out.println(str1); //java!
String str2 = strBuffer.substring(3, 9); // обрезка строки с 3 по 9 символ
System.out.println(str2); //lo jav
Изменение длины строки
Для изменения
длины строки класса StringBuffer (но не емкости буфера символов) применяется
метод setLength(). При увеличении строки в ее конец просто добавляются пробелы,
если же строка уменьшается, то она обрезается:
StringBuffer strBuffer = new StringBuffer("hello");
strBuffer.setLength(10);
System.out.println(strBuffer.toString()); //"hello "
strBuffer.setLength(4);
System.out.println(strBuffer.toString()); //"hell"
Замена подстроки в строке
Для замены
подстроки между определенными позициями на другую подстроку применяется метод
replace():
Первый параметр
метода replace указывает, с какой позиции надо начать замену, второй параметр -
до какой позиции, а третий параметр указывает на подстроку замены.
Обратный порядок в строке
Метод reverse()
меняет порядок символов в StringBuffer на обратный:
Вот основные
методы классов StringBuffer и StringBuilder.