Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

только для чтени

Работа добавлена на сайт samzan.net:


ГЛАВА 9

Строки

Что пользы в цитате, если нельзя изменить ее?

Dr. Who, The Two Doctors 

Строки (strings) - это стандартные объекты, поддерживаемые на уровне языка. Вы уже видели немало примеров создания объектов строк с помощью строковых литералов. Мы упоминали также операторы + и +=, служащие для сцепления нескольких строк в одну новую строку. Класс String, однако, предлагает множество дополнительных функциональных возможностей. Объекты String обладают свойством устойчивости к изменениям ("только для чтения"), поэтому в Java предусмотрен класс StringBuffer, содержимое объектов которого допускает модификацию в ходе выполнения программы. В этой главе мы подробно расскажем о классах String и StringBuffer, а также осветим вопросы преобразования строк в объекты других типов, таких как целочисленные и булевы значения.

9.1. Основные операции со строками

Класс String служит для представления неизменяемых строк и предлагает методы их обработки. Строки могут быть созданы неявно посредством задания литералов (таких как "GroBe") либо при использовании операторов + или += для сцепления содержимого двух объектов String с образованием новод строки.

Допускается и явное создание объектов String с помощью оператора new.

Класс String поддерживает несколько простых конструкторов (остальные мы рассмотрим в следующих разделах).

Public String()

Создает новый объект String со значением “” - пустую строку.

public String(String value)

Конструктор копии - создает новый объект String, служащий копией объекта-параметра value. Поскольку объекты String обладают свойством устойчивости, применяется редко.

К наиболее употребительным методам класса String можно отнести length и charAt. Метод length возвращает целочисленное значение, равное количеству Символов в строке, а charAt - значение типа char, отвечающее символу строки, который расположен на указанной позиции (в этом смысле строки схожи с массивами символов). Ниже приведен пример цикла, в котором подсчитывается Частота появления каждого символа в пределах заданной строки:

for (int i = 0; i < str.length(); i++)

counts[str.charAt(i)]++;

Обратите внимание, что 1ength - это метод класса String, а массивы обладают одноименным полем (новички часто их путают).

При использовании большинства методов класса String задание значения позиции символа в строке, меньшего нуля или превышающего величину length - 1, приводит К выбрасыванию исключения типа IndexoutOfBoundsException; в Некоторых реализациях поддерживается производный тип исключения StringIndexOutOfBoundsException, который предусматривает передачу Конструктору неверного значения, включаемого затем в подробное сообщение об ошибке. (Исключение типа IndexoutOfBoundsException генерируется также в случае Попытки доступа к элементу массива с заданием неверного значения индекса.)

В составе класса String имеется ряд простых методов поиска в строке заданных символов или подстрок. Следующий пример демонстрирует, каким образом можно подсчитать количество символов, разделяющих первый и последний экземпляры заданного символа ch в указанной строке str:

public static int countBetween(String str, char ch) {

int begpos = str.indexOf(ch);

 if (begpos < О) // Символа в строке нет

return -1;

int endpos = str.lastIndexOf(ch);

return endpos - begpos - 1;

}

Метод countBetween находит позиции первого и последнего экземпляров символа ch в строке str. Если символ не встречается в строке, самое меньшее, дважды, метод возвращает значение -1. Разность значений двух позиций символов в строке на единицу превышает число символов между ними (если первый и последний экземпляры символа расположены, скажем, на позициях 2 и 3, тогда число символов между ними равно нулю).

В таблице, приведенной ниже, перечислены перегруженные формы метода indexOf, позволяющие осуществлять поиск с начала строки, и варианты метода lastIndexOf, начинающие отсчет с конца строки. Каждый из методов в случае успешного завершения поиска возвращает значение найденной позиции символа или подстроки, а при неудаче - число -1.

Метод      Возвращает значение позиции…

indexOf(char ch)    первого экземпляра символа ch

indexOf(char ch, int start)   первого экземпляра символа ch, начиная с позиции, не меньшей       start

indexOf(String str)    первого экземпляра подстроки str

indexOf(String str, int start)  первого экземпляра подстроки str, начиная с позиции, не        меньшей start

lastIndexOf(char ch)    последнего экземпляра символа ch

lastIndexOf(char ch, int start)  последнего экземпляра символа ch, начиная с позиции, не        большей start

226           ГЛАВА 9. строки

Метод      Возвращает значение позиции…

lаstIndехоf(stгing str)   последнего экземпляра подстроки str

lastIndexOf(string str, int start)  последнего экземпляра подстроки str, начиная с позиции, не большей start

Упражнение 9.1. Создайте метод, который подсчитывает количество экземпляров заданного символа в указанной строке.

Упражнение 9.2. Создайте метод, который подсчитывает количество экземпляров заданной подстроки в указанной строке.

9.2. Сравнение строк

Класс String поддерживает механизмы сравнения строк и их отдельных частей. Прежде чем приступить к описанию соответствующих методов, мы должны предупредить, что все они основаны на модели строки, отвечающей спецификации Unicode, и поэтому не принимают в расчет региональные стандарты и вопросы, связанные с локализацией кода. Например, при выполнении операции сравнения строк на предмет того, какая из них "больше", про грамма сопоставляет Uпiсоdе-коды каждого символа обеих строк, но не руководствуется правилами какого-либо конкретного естественного языка. С точки зрения франкоязычного пользователя, например, буквы с и с считаются одинаковыми и различаются только наличием во второй из них диакритического знака. При сортировке строк текста, набранного по-французски, принято игнорировать подобные различия - строка "асb", скажем, будет размещена перед строкой "acz", поскольку буква Ь в алфавите французского языка предшествует букве z. Но в соответствии с правилами Unicode указанные символы приходится считать совершенно различными - в таблице символов Unicode буква с (\uООБЗ) находится перед С (\иООе7), - поэтому Jаvа-программа отсортирует строки по-другому. Вопросы, относящиеся к проблематике региональных стандартов и локализации, освещены в главе 19.

Первый метод сравнения строк, которому следует уделить внимание, - это equals; он возвращает true, если переданный аргумент типа String ссылается На строку с таким же набором символов, который хранится и в текущей строке, Т.е. обе строки обладают одинаковой длиной и в точности теми же символами Unicode, расположенными в одинаковом порядке. Если же аргумент относится к Типу, отличному от String, либо обладает иным содержимым, String.equals Возвращает false. Как мы упоминали в разделе 3.8 на странице 109, такое поведение, предполагающее замену условия тождественности ссылок условием равнозначности содержимого, переопределяет исходные правила, которым следует метод Object.equals.

Для сопоставления строк при условии пренебрежения регистром символов ПРИ меняется метод equalsIgnoreCase. Говоря о "пренебрежении регистром", Мы подразумеваем, что, скажем, символы Ё и ё считаются равнозначными и отличными от Е и е. Символы, для которых не существует аналогов в других регистрах (такие как знаки пунктуации), при сопоставлении считаются равными Только самим себе. Спецификация Unicode предлагает немало любопытных возможностей, связанных с регистром символов, включая, например, понятие реги-

9.2. СРАВНЕНИЕ строк           227

стра заголовка (titlecase). Обработка признака регистра в объектах Stгing выполняется согласно правилам, которым следуют соответствующие методы класса charachter, подробно рассмотренного в разделе 11.1.3 на странице 290.

Для выполнения сортировки строк необходим способ их взаимного сравнения.

Метод compareTo класса String возвращает значение типа int, меньшее нуля, равное нулю или большее нуля, если соответственно строка, представляемая текущим объектом, меньше строки, переданной в качестве параметра метода, равна ей или больше нее. Упорядочение символов выполняется по правилам Unicode. Класс String содержит две перегруженные версии метода compareTo: Первой в виде аргумента передается объект типа String, а второй - объект Object. Класс реализует интерфейс comparable, о котором мы упоминали в разделе 4.1 на странице 126, и второй из названных методов выполняет преобразование параметра Object к типу Stгing, вызывая затем первую версию метода compareTo. Существует также и метод compareToIgnorecase, Выполняющий сравнение без учета регистра символов.

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

private String[] table;

public int position(String key) {

int 10 = 0;

int hi = table.length - 1;

while (10 <= hi) {

int mid = 10 + (hi - 10) / 2;

int стр = key.compareTo(table[mid]);

 if (стр == о)  // Элемент найден

return mid;

else if (стр < о)  // Поиск в нижней части списка

hi = mid - 1;

else  // Поиск в верхней части списка

10 = mid + 1;

}

return -1;      // Элемент не найден

}

в представленном коде реализован базовый алгоритм бинарного поиска. Сначала вычисляется средняя позиция (mid) диапазона и проверяются условия равенства или неравенства ключевого элемента (key) и элемента, расположенного на этой позиции. Если элементы совпадают, значит, поиск завершен успешно. Если ключевой элемент меньше элемента, занимающего среднюю позицию, диапазон сокращается до нижней половины; в противном случае далее будет просматриваться верхняя половина диапазона. Процесс повторяется до тех пор, пока в списке не будет найден искомый ключевой элемент либо значение нижней границы текущего диапазона не превысит величину верхней границы, свидетельствуя о том, что ключевой элемент в списке отсутствует.

228          ГЛАВА 9. строки

Сопоставляться могут не только целые строки, но и их отдельные части. Подобные функции выполняет метод regionMatches, который реализован в двух формах, представленных ниже.

public boolean regionMatches(i~t start, String other, int ostart, lnt count)

Метод возвращает true, если каждый символ заданного фрагмента текущей строки совпадает с соответствующим символом фрагмента строки, переданной посредством ссылки оthег. Анализу подвергаются часть текущей строки, начиная с символа на позиции start, и фрагмент строки other, начиная с позиции ostart. Количество символов, участвующих в сравнении, задается значением count.

public boolean regionMatches(Boolean ignoreCase, int start, String other, int ostart, lnt count)

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

Первая операция сравнения дает итог, равный false, поскольку на позиции текущей строки находится символ ‘и’, а на позиции 0 литерала "ищи" - символ 'и'. Во втором случае мы разрешаем про грамме пренебречь различиями в регистре символов, поэтому результат сравнения фрагментов строк равен true. При выполнении третьей операции сравнения мы вновь получаем false, поскольку длина сопоставляемых фрагментов равна теперь 4 и их символы не совпадают даже при игнорировании регистра.

В методах, подобных regionMatches, задание неверных значений позиций внутри строки влечет получение результата false и не приводит к выбрасыванию исключений. Если в качестве значения ссылочного параметра передается null, генерируется исключение типа NullРоInterException.

9.2. СРАВНЕНИЕ строк           229

Простые операции проверки содержимого начальной и Конечной частей строки могут быть выполнены с помощью методов startsWith и endsWith.

public boolean startswith(string prefix, int  start)

Возвращает true, если в текущей строке, начиная с позиции start

расположена последовательность символов prefi х.  '

public boolean startsWith(string prefix)

Метод аналогичен предыдущему при условии startsWith (prefiх, 0). public boolean endsWith(String suffix)

Возвращает true, если текущая строка завершается последовательно символов suffiх.

9.2.1. Равнозначность строковых литералов

Оператор ==, применяемый для сравнения строк, вообще говоря, дает неверные результаты. Рассмотрим пример:

if (str == "2,pena?")

answer(str);

Такой код не позволяет сравнивать содержимое двух строк - напротив, он сопоставляет одну объектную ссылку (str) с другой (строковым объектом, представляемым литералом " 2, Репа?"). Даже если Str действительно содержит строку " 2, Репа?", оператор == все равно почти всегда возвратит false, поскольку две строки принадлежат совершенно различным объектам. Оператор == на самом деле позволяет проверить только тот факт, указывают ли две ссылки на один и тот же объект, и не предназначен для контроля равнозначности содержимого объектов.

Однако принято считать, что два строковых литерала с одинаковым содержимым указывают на один и тот же объект String. В рассмотренном ниже случае оператор == будет действовать верно.

String str = "2,pena?"; //

if (str == "2,pena?")

answer(str);

Поскольку переменная str изначально проинициализирована литеральным значением, сопоставление ее с другим строковым литералом равносильно сравнению содержимого двух строк. Впрочем, будьте внимательны - подобный код работает корректно только в тех случаях, когда ссылки действительно указывают на строковые литералы. Если в процессе выполнения про граммы ссылка Str была изменена и теперь указывает на объект String, созданный динамически (например, в результате ввода пользователем последовательности символов), оператор == возвратит false даже в том случае, если пользователь ввел ту же строку - "2, Репа?".

9.3. Прикладные методы

В составе класса String есть два метода, полезных для использования в специальных приложениях. Один из них носит название hashCode и возвращает хеш-код объекта на основании содержимого строки. Любые две строки с одинаковым содержимым будут обладать совпадающими хеш-кодами, хотя один и тот же хеш-код может быть вычислен и для различных строк. Хеш-коды объектов

230          ГЛАВА 9. строки

 находят применение в классах коллекций - таких как класс HashMap из пакета java.util, который мы рассмотрим в разделе 16.7.1 на странице 455.

Другой прикладной метод класса String, достойный внимания, - это intern, возвращающий новую строку с тем же содержимым, что и в текущем объекте String. Любые два объекта String с одинаковым содержимым возвращают посредством метода intern в точности тот же объект String - это позволяет существенно быстрее сопоставлять "внутренности" объектов, сравнивая ссылки на них. Рассмотрим пример:

/ / ...

String[] table;

// инициализация элементов массива table посредством вызовов

intern int tableCurrentSize = ... // Сколько элементов проинициализировано

/ / ...

int putIn(string key) {

String unique = key.intern();

int i;

// проверяем, присутствует ли unique в table ...

for (; = о; i < tableCurrentsize; i++)

if (table[i] == unique)

return i;

// ЕСЛИ нет, добавляем unique в table

table[i] = unique;

tableCurrentSize++;

return i;

}

Массив tablе просматривается в поисках строки, которая была получена в результате вызова метода intern в объекте другой строки, обладающей тем же содержимым, что и key. Если такая строка найдена, поиск завершается. Если же результат поиска отрицателен, значение unique, полученное при вызове key. intern (), сохраняется в массиве. Использование при сравнении строк результатов вызовов метода intern равносильно непосредственному сопоставлению содержимого строк, но выполняется значительно быстрее.

9.4. Обработка строк

В составе класса String существует ряд методов, возвращающих новые строки, равнозначные текущей с учетом определенных изменений. Следует подчеркнуть, что возвращаются именно н-овые строки, поскольку объекты String обладают свойством устойчивости к изменениям.

publiс static String delimitedString( String from, char start, char end)

{

int startpos = from.indexOf(start);

int endpos ~ from.lastIndexOf(end);

if (startpos > endpos)

// Начальный разделитель расположен после конечного return null;

9.4. ОБРАБОТКА СТРОК           231

else if (startpos == -1)

// нет начального разделителя return null;

else if (endpos == -1)

// Нет конечного разделителя return from.substring(startPos); else

// оба разделителя найдены 

return from.substring(startPos, endpos + 1);

}

Метод delimitedString возвращает новый объект String, содержащий часть Исходной строки from, ограниченную символами-разделителями start и end, т.е. Начинающуюся символом start и завершающуюся символом end. Если символ start найден, а end - нет, метод возвращает новый объект String, содержащий часть строки from, начиная с символа start и до конца from. Метод оперирует двумя Перегруженными формами стандартного метода substring. Первая версия substring требует задания начальной позиции в исходной строке и возвращает ее часть, начиная с этой позиции и до конца строки. Вторая форма метода предполагает передачу двух параметров, представляющих начальную и конечную позиции в строке, и возвращает новую строку, содержащую все символы исходной, начиная с начальной Позиции и завершая конечной позицией, причем последний символ в итоговую строку не включается. Поэтому в аргументе последней инструкции кода к значению endpos прибавлена единица - таким образом метод гарантирует, что в строку-результат попадет и символ конечного разделителя. Например, при выполнении команды

delimitedString("Ilаdit «Bonjour!»", '«', '»'); результатом будет 

«Bonjour!»

Ниже приведена информация о других методах обработки строк. public String replace(char oldСhar, char newСhar)

Возвращает новый объект String, в котором все экземпляры символа oldСhar заменены символами newСhar.

public String trim()

Возвращает новый объект String, в котором удалены все начальные и конечные символы пробелов.

Задачи преобразования регистров символов связаны с вопросами локализации - они решаются по-разному, в зависимости от существующих местных традиций и особенностей той или иной культуры. Платформа Java позволяет пользователям выбирать необходимый региональный стандарт, в котором, в частности, учтены и правила преобразования регистра символов. Информация о региональных стандартах представляется с помощью объектов класса Localе, который подробно рассмотрен в главе 19. При отсутствии явно заданного аргумента типа Localе методы toLowerCase и toUpperCase, описанные ниже, оперируют текущими значениями Localе, принятыми по умолчанию.

public String toLowerCase()

Возвращает новый объект String, в котором каждый символ заменен аналогом в нижнем регистре (если таковой предусмотрен в регионально в стандарте, применяемом по умолчанию).

232          ГЛАВА 9. СТРОКИ 

public String toUpperCase()

Возвращает новый объект Stгing, в котором каждый символ заменен аналогом в верхнем регистре (если таковой предусмотрен в региональном стандарте, применяемом по умолчанию).

public String toLowerCase(Locale lос)

Возвращает новый объект String, в котором каждый символ заменен аналогом в нижнем регистре (если таковой предусмотрен в региональном стандарте, заданном в качестве параметра).

public String toUppercase(Locale lос)

Возвращает новый объект String, в котором каждый символ заменен аналогом в верхнем регистре (если таковой предусмотрен в региональном стандарте, заданном в качестве параметра).

Метод concat возвращает новую строку, которая служит результатом сцепления (конкатенации) двух строк. Следующие инструкции кода равнозначны:

newStr = oldStr.concat(" еще");

newstr = oldStr + " еще";

Упражнение 9.3. Рассмотренный выше метод delimitedStгing предусматривает возможность поиска в исходной строке только одной, самой "длинной" строки, ограниченной заданными символами-разделителями. Напишите версию метода, который способен возвращать массив всех экземпляров "коротких" строк, удовлетворяющих тому же условию.

9.5. Преобразование строк

Часто возникает необходимость преобразования строк в значения других типов, таких как int или boolean, и наоборот. В соответствии с принятым соглашением ответственность за преобразование строки в значение другого типа возложена на соответствующий метод этого типа. Так, например, преобразование строки в величину типа int выполняет статический метод из состава класса-оболочки Integer. В следующей таблице указаны все типы, допускающие преобразование значений в строки и наоборот, и перечислены соответствующие методы.

 ТИП  Метод для преобразова-  Метод для преобразования из строки

ния В строку 

boolean String.valueOf(boolean) new.Boolean(String). booleanvalue()

byte  String.valueOf(byte)  Byte.parseByte(string, int)

short  String.valueOf(short)  Short.parseShort(string, int)

int  String.valueOf(int)  Integer.parseInteger(string, int)

long  String.valueOf(long)  Long.parseLong(String, int)

float  String.valueOf(float)  Float.parseFloat(String)

 double  String.valueOf(double) Double.parseDouble(String)

Для преобразования строки в значение Boolean необходимо создать объект Boolean и затем запросить его значение. Все остальные классы-оболочки содержат Соответствующие методы parse. Методы parse целочисленных типов существуют в двух перегруженных формах: первая, помимо строки, требует задания

9.5. ПРЕОБРАЗОВАНИЕ СТРОК         233

дополнительного аргумента типа int, представляющего основание системы счисления - от 2 до 32; вторая принимает только параметр строки и по умолчанию предполагает использование десятичной системы счисления. Во всех случаях, кроме Boolean, предполагается следующее: если строка представляет значение, которое не может быть корректно преобразовано в число соответствующего типа, выбрасывается исключение NumberFormatException. Класс Boolean удовлетворяет соглашению, в соответствии с которым любая строка-параметр, не равная "true" (без учета регистра символов), приводит к созданию объекта вооlеаn со значением false.

Методов, позволяющих преобразовать символы, которые представлены в одной из поддерживаемых языком форм (таких как \b, \uxxxx и т.д.), В значения типа char и наоборот, не существует. Чтобы получить объект String, содержащий единственный символ, достаточно вызвать метод String.valueOf, передав ему в качестве параметра соответствующее значение типа char.

Отсутствуют также и способы создания строковых представлений чисел, заданных в одном из поддерживаемых языком форматов - с ведущим нулем (О), обозначающим восьмеричное число, и префиксом Ох (или ОХ), служащим признаком шестнадцатеричной системы счисления. Напротив, в целочисленных классах-оболочках поддерживаются версии метода decode, способного преобразовать строки в числовые значения соответствующего типа и "понимающего", что ведущий О обозначает восьмеричное число, а один из префиксов Ох ИЛИ Ох - шестнадцатеричное.

Любой прикладной класс способен обеспечить поддержку преобразований собственных объектов в строки и обратно, если в его объявлении будет соответствующим образом переопределен метод toString и предусмотрен специальный конструктор, создающий объект класса на основе строки, переданной в качестве параметра. В вашем распоряжении имеется также метод String.valueOf(Object obj), который возвращает либо строковый объект "null" (если значение obj равно null), либо результат работы метода obj.toString. Класс String содержит достаточное количество перегруженных версий метода valueOf, позволяющих преобразовать любое значение любого типа в объект String посредством простого вызова valueOf с передачей нужного аргумента.

9.6. Строки и массивы значений char

Содержимое объекта String может быть отображено с помощью массива элементов типа char и наоборот. Достаточно часто возникает задача построения массива значений char, а на его основе - объекта типа String. В тех ситуациях, когда применение объектов класса StringBuffer (обратитесь к разделу 9.8 на странице 237), допускающих изменение строковых данных, нецелесообразно или неудобно, можно обратиться к нескольким методам и конструкторам класса Stri ng, помогающим преобразовать объект типа String в массив значений char либо, наоборот, массив char - в объект String.

Существуют два конструктора, позволяющих создавать объекты String на основе массивов значений char.

public String(char[] chars, int start, int count)

Создает новый объект String, содержимое которого соответствует части последовательности элементов массива chars, берущей начало с элемента под номером start и содержащей не больше count символов.

234          ГЛАВА 9. строки

public String(char[] chars)

Конструктор аналогичен предыдущему при условии String ( chars, 0 , chars.length).

оба конструктора предусматривают копирование передаваемого массива, так что, создав объект String, вы вправе изменить положенный в его основу Массив, не рискуя исказить содержимое объекта String.

следующий простой пример демонстрирует способ удаления из строки всех экземпляров определенного символа:

public static String squeezeOut(string from, char toss) {

char[] chars = from.toCharArray();

int len = chars.length;

int put = о;

for (int i = о; i < len; i++)

if (chars[i] != toss) chars[put++] = chars[i]; return new String(chars, О, put);

}

Метод squeezeOut осуществляет преобразование содержимого строки-параметра from в массив chars типа char с помощью метода toCharArray. Далее вычисляется длина исходного массива и инициализируется переменная put, предназначенная для хранения значения позиции, свободной для присваивания очередного пере носимого символа. Внутри цикла очередной символ сравнивается с образцом и при отрицательном результате пере носится на позицию, задаваемую величиной put. По завершении цикла метод возвращает новую строку, созданную на основании массива, из которого удалены все экземпляры символа-образца.

При необходимости вместо конструкторов можно воспользоваться одним из двух соответствующих статических методов Stгing.copyValueOf. Например, последнюю инструкцию метода squeezeOut легко переписать следующим образом:

return String.copyvalueOf(chars, О, put);

Вторая версия метода String. copyvalueOf предусматривает задание одного параметра и преобразует в String массив значений char целиком.

Метод toCharArray достаточно прост и способен удовлетворить почти любые Потребности. Если нужны более изощренные средства управления переносом фрагментов строки в массив символов, можно обратиться к методу getChars, Описанному Ниже.

public void getChars(int srcBegin, int srcEnd, char[] dst,

int dstBegin)

Копирует символы из фрагмента текущей строки, заданного значениями начальной (srcBegin) и конечной (srcEnd) позиций, в указанный массив dst значений char, начиная с элемента dst[dstBegi n]. Элемент Исходной строки с индексом, равным srcEnd, не копируется.

9.7. Строки и массивы значений byte

В Составе класса String существует ряд методов, позволяющих преобразовывать массивы 8-битовых символов в 16-битовые строки Unicode и наоборот. Подобные преобразования выполняются с учетом принятой кодировки и их резуль-

9.7. СТРОКИ И МАССИВЫ ЗНАЧЕНИЙ ВУТЕ         235

таты существенно зависят от источника происхождения Символов. Например, массив байтов формата ASCII или Latin-l преобразуется в последовательность символов Unicode совершенно прозрачно, путем добавления нулевых старших байтов, но такой подход неприемлем при использовании символов в других Кодировках - скажем, букв иврита. Ниже рассмотрены конструкторы и методы, которые позволяют явно задавать вид требуемой кодировки либо применять Кодировку, выбранную конкретным пользователем или предлагаемую платформой Java по умолчанию.

public String(byte[] bytes, int start, int count) Создает новый объект String путем преобразования массива bytes, начиная с байта под номером start, кодировкой символов и региональным стандартом, умолчанию.

public String(byte[] bytes)

Конструктор аналогичен предыдущему при условии String(bytes, 0, bytes.length).

public String(byte[] bytes, int start, int count, String еnс)

throws UnsupportedEncodingException

Создает новый объект String путем преобразования count элементов массива bytes, начиная с байта под номером start, в соответствии с кодировкой символов, наименование которой задано параметром еnс.

public String(byte[] bytes, String еnс) throws UnsupportedEncodingException

Конструктор аналогичен предыдущему при условии String (bytes, О, bytes.length, еnс).

public byte[] getBytes()

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

public byte[] getBytes(String еnс)

throws UnsupportedEncodingException

Возвращает массив байтов текущей строки, преобразованных в соответствии с кодировкой символов, наименование которой задано параметром еnс.

Конструкторы String, предусматривающие возможность построения строк на основе массивов типа byte, выполняют копирование данных, поэтому последующее изменение содержимого массива не оказывает влияния на созданный объект String.

9.7.1. Стандарты кодировки символов

Стандарт кодировки регламентирует правила взаимного преобразования 8 битовых символов и их 16-битовых аналогов формата Unicode. Кодировкам присваиваются соответствующие наименования. Конкретная платформа Java определяет, с какими кодировками она способна работать, но в любом случае поддерживаются кодировки, указанные в следующей таблице.

236          ГЛАВА 9. строки

Кодировка  Описание

US-ASCII 7-битовый формат ASCII, известный также как 150б4б-us и набор BA51C_LAT1N в таблице символов Unicode

ISO-8859-1  Алфавит номер 1 ISO Latin, известный также как IS0- LAT1N-1

UTF-8   8-битовый формат преобразования Unicode (Unicode Transformation Format - UTF)

UTF-16BE  16-битовый UTF с порядком следования байтов "старший байт в конце" (big-endian)

UTF-16LE  16-битовый UTF с порядком следования байтов "младший байт в конце" (Iittle-endian)

UTF-16 16-битовый UTF; порядок следования байтов определяется специальным обязательным маркером (либо задается при вводе - тогда при выводе используется порядок big-endian)

За сведениями о том, поддерживаются ли в используемой вами конкретной реализации Java другие кодировки, обращайтесь к сопроводительной документации.

Чтобы проверить, поддерживается ли определенная кодировка, попытайтесь создать объект строки на основе пустого массива значений byte с заданием имени кодировки: если при этом генерируется исключение типа UnsupportedEncodingException, кодировка не поддерживается.

Каждый экземпляр виртуальной машины Java по умолчанию отдает предпочтение определенной кодировке символов. Выбор кодировки выполняется при старте машины и обычно зависит от параметров регионального стандарта и кодировки символов, установленных для операционной системы.

9.8. Класс StringBuffer

Если бы класс String, который представляет объекты строк, не допускающих изменения, был единственным доступным средством, в процессе обработки строковых данных для хранения промежуточных результатов нам пришлось бы создавать новые объекты String. В качестве примера рассмотрим последовательность действий компилятора при вычислении следующего выражения:

public static String guillemete(string quote) {

return '«' + quote + '»';

}

Если бы компилятор был ограничен возможностью использования только тех объектов, которые относятся к классу String, выполняемые им операции можно было бы описать такой схемой:

quoted = String.valueOf('«').concat(quote)

.concat(string.valueOf('»'));

При Каждом вызове valueOf и concat создается новый объект String, так что в Процессе вычисления рассматриваемого выражения системе пришлось бы построить четыре объекта String, только один из которых пригодился бы в дальнейшем, и понести при этом неоправданно большие накладные расходы, связанные с созданием, инициализацией и утилизацией дополнительных объектов.

9.8. КЛАСС StringBUFFER           337

На самом деле, однако, компилятор действует более эффективно. В процессе вычислений промежуточных результатов он использует объект класса StringBuffer и создает объект String только в том случае, когда это действительно необходимо. Объекты StringBuffer допускают изменение содержимого, поэтому создавать новые объекты для хранения промежуточных результатов вычислений не требуется. Вычисляя выражение с помощью средств класса StringBuffer, компилятор выполняет следующие операции:

quoted= new StringBuffer().append('«') appendCquote).append('»').toString();

В процессе вычисления выражения компилятор создает единственный объект StringBuffer для хранения всей последовательности символов, инициализирует его посредством нескольких функций append, а затем с помощью метода tostring преобразует Окончательный результат в объект типа String.

Для построения и изменения строк вы вправе воспользоваться средствами Класса StringBuffer непосредственно. В его составе есть несколько конструкторов, описанных ниже.

public StringBuffer()

Создает новый объект StringBuffer со значением "" - пустую строку.

public StringBuffer(String str)

Создает новый объект StringBuffer, содержащий ту же строку, что и объект-параметр stг.

Класс StringBuffer во многом подобен Классу String он поддерживает ряд одноименных методов с теми же контрактами. Однако StringBuffer не является производным от String, поэтому обратное предположение также неверно. Эти классы совершенно независимы - они оба наследуют класс Object.

9.8.1. Изменение содержимого объектов StringBuffer

Существует несколько способов изменения содержимого объекта типа StringBuffer, Включая добавление символов в Конец и вставку их в середину строки. setCharAt, один из самых простых методов, позволяет заменить символ в Указанной позиции строки. Ниже рассмотрен пример метода гер1асе, который, выполняя те же функции, что и String. replace, Т.е. заменяя все Экземпляры одного заданного символа другим, оперирует объектом StringBuffer и позволяет избежать необходимости создания нового объекта строки.

public static void

replace(stringBuffer str, char oldСhar, char newСhar) {

for (int i = о; i < str.length(); i++)

if (str.charAtCi) == oldСhar)

str.setCharAtCi, newСhar);

}

Метод setLength Класса StringBuffer выполняет усечение или удлинение строки до Указанной длины. Если при вызове setLength задается число, меньшее текущей длины строки, строка соответствующим образом Укорачивается. Если же методу передается значение, превышающее текущую длину строки, строка дополняется пустыми символами ( '\uOOOO' ).

238           ГЛАВА 9. строки

в составе класса StringBuffer определены также наборы методов append и insert, позволяющие преобразовать значение любого типа в строку, а затем присоединить результат в конец (append) либо вставить его в середину буфера (insert). Методы insert сдвигают символы строки, начиная с указанной позиции, вправо, чтобы подготовить место, достаточное для вставки новой порции данных в следующей таблице перечислены все типы, значения которых могут быть преобразованы соответствующими перегруженными вариантами методов

append и insert.

Существуют также такие формы методов append и insert, которые способны принимать в качестве параметра часть массива типа char. Ниже рассмотрен пример кода, который, обращаясь к различным вариантам метода append, позволяет создать объект String, содержащий строку с результатом вычисления квадратного корня целочисленного аргумента.

string sqrtlnt(int i) {

StringBuffer buf = new StringBuffer();

buf. append (" sqrt (") . append (i) . append (') ') ;

buf.append(" = ").append(Math.sqrt(i));

return buf.toString();

}

Методы append и i nsert возвращают ссылки на текущий объект StringBuffer, что позволяет при очередном вызове метода использовать результат предыдущего вызова.

Методы insert в качестве параметров принимают два значения: первое указывает позицию в строке StringBuffer, куда следует вставить значение второго параметра после необходимого преобразования его в объект String. Вот так можно поместить в начало буфера строку, содержащую значение текущей даты:

public static StringBuffer addDate(stringBuffer buf) {

String now = new java.util.Date().toString();

buf.insert(0, now).insert(now.length(), ": ");

return buf;

}

Метод addDate сначала создает строку, содержащую значения текущей даты и времени; с этой целью применяется стандартный класс java.util . Date, конструктор которого, используемый по умолчанию, строит объект, хранящий информацию о дате и времени своего создания. Объект типа Date преобразуется в строку, Которая вставляется в начало буфера buf; за ней вставляется литерал-разделитель. Наконец, метод возвращает ссылку на прежний, но уже дополненный буфер, который передан в качестве параметра. Таким образом, здесь мы используем тот же прием возврата ссылки на объект StringBuffer, переданной ранее в виде параметра. Этот прием, реализованный в стандартных методах класса StringBuffer, доказал свою полезность, поскольку позволяет записывать в виде единого выражения целую цепочку вызовов методов.

239         9.8. КЛАСС StringBUFFER

Метод reverse перестраивает порядок следования символов в строке StгingBuffer на обратный. Так, например, если в буфере хранилось значение "кот", после вызова reverse оно будет преобразовано в ток.

От части строки буфера нетрудно избавиться, если воспользоваться методом delete, которому следует передать значения начальной и конечной позиций символов, подлежащих удалению. Указанный сегмент строки (за исключением символа, отвечающего конечной позиции) изымается, и строка укорачивается. Чтобы удалить из строки единственный символ, можно воспользоваться методом deleteCharAt.

Существуют и более сложные формы методов замены и вставки символов.

public StringBuffer replace(int start, int end, String str) Заменяет фрагмент строки, задаваемый позициями начала (start) и конца (end, этот символ не учитывается), содержимым параметра str. Буфер удлиняется или сокращается в зависимости от того, что длиннее - строка str или заменяемый диапазон символов.

public StringBuffer insert(int pos, char[] chars, int start,

int count)

Вставляет в строку буфера, начиная с позиции pos, символы маСсива chars и сдвигает при этом символы буфера вправо, освобождая место, достаточное для вставки элементов chars. Из chars копируется count символов, начиная с элемента chars [start].

9.8.2. Обработка объектов StringBuffer

Чтобы получить объект String из объекта StringBuffer, достаточно вызвать метод toString последнего. Для извлечения части буфера применяются методы subString, аналогичные тем, которые имеются в составе класса String. Если необходимо представить содержимое буфера или его фрагмента в виде массива элементов типа char, можно воспользоваться методом getchars, подобным методу String .getchars.

public void getchars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

Копирует символы текущей строки StringBuffer в заданный массив dst. При этом символы строки из диапазона, заданного параметрами srcBegin и srcEnd (символ на позиции srcEnd не учитывается), присваиваются элементам массива, начиная с dst [dstBegi n].

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

public static StringBuffer

remove(StringBuffer buf, int pos, int cnt)

{

if (pos < 0 II cnt < 0 II pos + cnt > buf.length()) throw new IndexoutOfBoundsException();

int leftover = buf.length() - (pos + cnt);

if (leftover == 0) { // простое отсечение части строки

buf.setLength(pos);

return buf;

}

240           ГЛАВА 9. строки 

char[] chrs = new char[leftover];

buf.getchars(pos + cnt, buf.length(), chrs, 0);

buf.setLength(pos);

buf.append(chrs);

return buf;

}

Сначала метод remove проверяет, принадлежат ли значения параметров pos и cnt допустимому диапазону. (Обработку исключения мы вправе выполнить позже, но зафиксировать факт возможной ошибки следует прямо здесь.) Затем подсчитывается количество символов строки, следующих за удаляемой частью. Если таковых  нет, часть строки просто отсекается. В противном случае эти символы извлекаются из строки с помощью метода getchars и запоминаются в массиве chrs, после чего буфер укорачивается, к нему присоединяются символы массива chrs и, наконец, искомая строка возвращается методом в виде буфера StringBuffer.

9.8.3. Контроль емкости буфера

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

Исходная емкость буфера объекта StringBuffer может быть задана посредством специального конструктора, который принимает в качестве параметра единственное значение типа int.

public StringBuffer(int capacity)

Создает объект StringBuffer заданной емкости с исходным значением, равным ""

public void ensurecapacity(int minimum)

Проверяет емкость буфера и при необходимости увеличивает ее до значения minimum.

public int capacity()

Возвращает значение текущей емкости буфера.

Используя эти методы, вы сможете избежать повинности постоянного наращивания емкости буфера. Ниже приведена новая версия метода sqrtlnt, рассмотренного в разделе 9.8.1 на странице 238, которая дает возможность задать необходимую и достаточную емкость буфера только один раз.

String sqrtlntFaster(int) {

StringBuffer buf = new StringBuffer(50);

buf.append("sqrt(") .append(i) .append(') ');

buf.append(" = ").append(Math.sqrt(i));

return buf.tostring();

}

Единственное внесенное нами изменение состоит в использовании другой версии Конструктора, которая создает объект StгingBuffer, достаточно емкий, чтобы

9.8. КЛАСС StringBUFFER           241

вместить итоговую строку. Значение 50, вероятно, несколько превышает требуемую величину; поэтому впоследствии увеличивать буфер не придется.

Упражнение 9.4. Напишите метод для преобразования строк, содержащих десятичные числа, в такую форму, где каждые три разряда числа, начиная С младшего, отделены символом запятой. Например, если дана строка "1234567"

метод должен вернуть строку "1,234,567".  '

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

 Когда воображение подводит. на помощь приходят слова.

      Иоганн Вольфганг фон ГёТе

242           ГЛАВА 9. строки




1. ЛЭТИ;. M. Кушнир кандидат психологических наук.html
2. Рок-музыка как признак и фактор социокультурной трансформации
3.  Задачи по изучению курса Предмет и метод истории отечественного государства и права её место в систе
4. Патриотическое воспитание граждан Российской Федерации на 2006 2010 годы Постановление Прав
5. Час здоровья и спорта Учебный час выделяемый на проведение данных занятий по согласованию с Министерств
6. темах тонального телеграфирования применяются модуляторы- все перечисленные В состав оконечных устройст
7.  Назовите не менее девяти характеристик фундаментальных и составных частиц
8. ТЕМА 3. РАЗНООБРАЗИЕ МОДЕЛЕЙ МЕНЕДЖМЕНТА
9. Кемеровский государственный университет Кафедра общей и региональной экономики Землянская Т
10. Характеристика административно-правовых средств обеспечивающих безопасность дорожного движени
11. Возрастные особенности психики старого человека
12. Соответственно большая группа определений трактует логистику как науку или научное направление- Логистик
13. Строение и номенклатура
14. Демографическая ситуация в Харьковской области
15. 3 В Петербурге назревала и переходила в критическую массу недовольство засильем иностранцев
16. Контрольная работа- Программное обеспечение Lotus-Note
17. Функционирование мясного подкомплекса сельскохозяйственной зоны Тюменской област
18. НіконПлюс здійснює розробки в галузі виробництва сучасних лінз та здійснює експорт інноваційної продукці
19. РЕФЕРАТ дисертації на здобуття наукового ступеня кандидата філологічних наук КИЇВ ~ Ди.1
20. 1 Сущность функции и классификация предпринимательской деятельности