Класс StringBuilder
Объекты класса StringBuilder — это строки переменной длины. Только что созданный объект имеет буфер определенной емкости (capacity), по умолчанию достаточной для хранения 16 символов. Емкость можно задать в конструкторе объекта.
Как только буфер начинает переполняться, его емкость автоматически увеличивается, чтобы вместить новые символы.
В любое время емкость буфера можно увеличить, обратившись к методу
ensureCapacity(int minCapacity);
Этот метод изменит емкость, только если minCapacity будет больше длины хранящейся в объекте строки. Емкость будет увеличена по следующему правилу. Пусть емкость буфера равна N. Тогда новая емкость будет равна
Max(2 * N + 2, minCapacity)
Таким образом, емкость буфера нельзя увеличить менее чем вдвое.
Методом setLength (int newLength) можно установить любую длину строки. Если она окажется больше текущей длины, то дополнительные символы будут равны 'u0000'. Если она будет меньше текущей длины, то строка окажется обрезанной, последние символы потеряются, точнее, будут заменены символом 'u0000'. Емкость при этом не изменится.
Если число newLength окажется отрицательным, возникнет исключительная ситуация. Совет
Будьте осторожны, устанавливая новую длину объекта.
Количество символов в строке можно узнать, как и для объекта класса String, методом
length (), а емкость — методом capacity ().
Создать объект класса StringBuilder можно только конструкторами.
Конструкторы
В классе StringBuilder четыре конструктора:
? StringBuilder () — создает пустой объект с емкостью 16 символов;
? StringBuilder (int capacity) создает пустой объект заданной емкости capacity;
? StringBuilder(String str) — создает объект емкостью str.length() + 16, содержащий строку str;
? StringBuilder(CharSequence str) — создает объект, содержащий строку str.
Как добавить подстроку
В классе StringBuilder есть более десяти методов append (), добавляющих подстроку в конец строки. Они не создают новый экземпляр строки, а возвращают ссылку на ту же самую, но измененную строку.
Основной метод append(String str) присоединяет строку str в конец данной строки. Если ссылка str == null, то добавляется строка "null".
Два аналогичных метода работают с параметром типа StringBuffer и CharSequence.
Шесть методов append(type elem) добавляют примитивные типы boolean, char, int, long, float, double, преобразованные в строку.
Два метода присоединяют к строке массив str и подмассив sub символов, преобразованные в строку:
append(char[] str);
append(char[] sub, int offset, int len);
Еще один метод, append(CharSequence sub, int offset, int len), использует параметр типа CharSequence.
Тринадцатый метод, append(Object obj), добавляет просто объект. Перед этим объект obj преобразуется в строку своим методом toString ( ).
Как вставить подстроку
Более десяти методов insert () предназначены для вставки строки, указанной вторым параметром метода, в данную строку. Место вставки задается первым параметром метода, индексом символа строки, перед которым будет сделана вставка. Он должен быть неотрицательным и меньше длины строки, иначе возникнет исключительная ситуация. Строка раздвигается, емкость буфера при необходимости увеличивается. Методы возвращают ссылку на ту же самую, но преобразованную строку.
Основной метод insert(int ind, String str) вставляет строку str в данную строку перед ее символом с индексом ind. Если ссылка str == null, вставляется строка "null".
Например, после выполнения
String s = new StringBuilder("3TO большая строка").
insert(4, "не").toString();
получим s == "Это небольшая строка".
Метод sb.insert(sb.length (), "xxx") будет работать так же, как метод sb.append("xxx").
Шесть методов insert(int ind, type elem) вставляют примитивные типы boolean, char,
int, long, float, double, преобразованные в строку.
Два метода вставляют массив str и подмассив sub символов, преобразованные в строку:
insert(int ind, char[] str);
insert(int ind, char[] sub, int offset, int len);
Десятый метод вставляет просто объект: insert(int ind, Object obj). Объект obj перед добавлением преобразуется в строку своим методом toString().
Еще два метода:
insert(int ind, CharSequence str);
insert(int ind, CharSequence sub, int start, int end); работают с параметром типа CharSequence.
Как удалить подстроку
Метод delete (int begin, int end) удаляет из строки символы, начиная с индекса begin включительно до индекса end исключительно; если end больше длины строки, то до конца строки.
Например, после выполнения
String s = new StringBuilderC^TO небольшая строка").
delete(4, 6).toString();
получим s == "Это большая строка".
Если begin отрицательно, больше длины строки или больше end, возникает исключительная ситуация.
Если begin == end, удаление не происходит.
Как удалить символ
Метод deleteCharAt(int ind) удаляет символ с указанным индексом ind. Длина строки уменьшается на единицу.
Если индекс ind отрицателен или больше длины строки, возникает исключительная ситуация.
Как заменить подстроку
Метод replace (int begin, int end, String str) удаляет символы из строки, начиная с индекса begin включительно до индекса end исключительно, а если end больше длины строки, то до конца строки, и вставляет вместо них строку str.
Если begin отрицательно, больше длины строки или больше end, возникает исключительная ситуация.
Разумеется, метод replace () — это последовательное выполнение методов delete ()
и insert().
Как перевернуть строку
Метод reverse () меняет порядок расположения символов в строке на обратный. Например, после выполнения
String s = new StringBuilderC^TO небольшая строка"). reverse().toString();
получим s == "акортс яашьлобен отЭ".
Синтаксический разбор строки
Задача разбора введенного текста — парсинг (parsing) — вечная задача программирования, наряду с сортировкой и поиском. Написана масса программ-парсеров (parser), разбирающих текст по различным признакам. Есть даже программы, генерирующие парсеры по заданным правилам разбора: YACC, LEX и др. Большую помощь в разборе строки оказывает метод split ().
Но задача остается. И вот очередной программист, отчаявшись найти что-нибудь подходящее, берется за разработку собственной программы разбора.
В пакет java.util входит простой класс StringTokenizer, облегчающий разбор строк.
Класс StringTokenizer
Класс StringTokenizer из пакета java.util небольшой, в нем три конструктора и шесть методов.
Первый конструктор, StringTokenizer(String str), создает объект, готовый разбить строку str на слова, разделенные пробелами, символами табуляции ' ', перевода строки ' ' и возврата каретки ' '. Разделители не включаются в число слов.
Второй конструктор, StringTokenizer (String str, String delimeters), задает разделители вторым параметром delimeters, например:
StringTokenizer("Казнить,нельзя:пробелов-нет", " ,:-");
Здесь первый разделитель — пробел. Потом идут символ табуляции, символ перевода строки, символ возврата каретки, запятая, двоеточие, дефис. Порядок расположения разделителей в строке delimeters не имеет значения. Разделители не включаются в число слов.
Третий конструктор позволяет включить разделители в число слов:
StringTokenizer(String str, String delimeters, boolean flag);
Если параметр flag равен true, то разделители включаются в число слов, если false — нет. Например:
StringTokenizer("a — (b + c) / b * c", " +*-/()", true);
В разборе строки на слова активно участвуют два метода:
? метод nextToken () возвращает в виде строки следующее слово;
? логический метод hasMoreTokens () возвращает true, если в строке еще есть слова, и false, если слов больше нет.
Третий метод, countTokens (), возвращает число оставшихся слов.
Четвертый метод, nextToken(String newDelimeters), позволяет "на ходу" менять разделители. Следующее слово будет выделено по новым разделителям newDelimeters; новые разделители действуют далее вместо старых разделителей, определенных в конструкторе или предыдущем методе nextToken ( ).
Оставшиеся два метода, nextElement () и hasMoreElements (), реализуют интерфейс
Enumeration. Они просто обращаются к методам nextToken () и hasMoreTokens ().
Схема разбора очень проста (листинг 5.2).
Листинг 5.2. Разбиение строки на слова
import java.util.*; class MyParser{
public static void main(String[] args){
String s = "Строка, которую мы хотим разобрать на слова"; StringTokenizer st = new StringTokenizer(s, " ,.");
while(st.hasMoreTokens()){
// Получаем слово и что-нибудь делаем с ним, например // просто выводим на экран System.out.println(st.nextToken());
}
}
}
Полученные слова обычно заносятся в какой-нибудь класс-коллекцию: Vector, Stack или другой, наиболее подходящий для дальнейшей обработки текста контейнер. Классы-коллекции мы рассмотрим в следующей главе.
Заключение
Все методы представленных в этой главе классов написаны на языке Java. Их исходные тексты можно посмотреть, они входят в состав JDK. Это очень полезное занятие. Просмотрев исходный текст, вы получаете полное представление о том, как работает метод.
Исходные тексты хранятся в ZIP-архиве src.zip, лежащем в корневом каталоге JDK, например в каталоге D:jdk1.7.0.
После распаковки в каталоге jdk1.7.0 появится подкаталог, например, src, а в нем — подкаталоги, соответствующие пакетам и подпакетам JDK, с исходными файлами.
Вопросы для самопроверки
1. Зачем в язык Java введено несколько классов, обрабатывающих строки символов?
2. Какова разница между классами String и StringBuilder?
3. Какова разница между классами StringBuffer и StringBuilder?
4. Что лучше использовать для сцепления строк: операцию сцепления или метод append() класса StringBuilder?
5. Что лучше использовать для разбора строки: метод split() или класс StringTokenizer?
ГЛАВА 6