Читать книгу Визуальное программирование на Java Swing в NetBeans - Сергей Николаевич Талипов - Страница 8
1 Основные сведения
1.8 Работа со строками
ОглавлениеВ Java имеется три типа строк: String, StringBuilder и StringBuffer. Статические строки «String» – обычные строки в Java, в которых нельзя изменить символы и их количество после создания строки.
Динамические строки «StringBuilder» – изменяемые строки для использования в однопоточных программах. В однопоточном использовании StringBuilder практически всегда в 1.2-1.5 раза быстрее, чем StringBuffer.
Динамические строки StringBuffer – изменяемые строки для использования в многопоточных программах. Самый медленный тип, но потокобезопасный.
Переменные типа динамических строк могут менять свои значения и длину во время выполнения программы.
Статические строки. Обычные строки в Java описываются классом String и являются статическими, т.е. в существующей строке нельзя изменить символы и их количество.
Кроме стандартного создания оператором new, строки могут быть созданы напрямую из строковой литералы. При этом в целях оптимизации, объекты созданные таким образом дополнительно сохраняются в отдельной области – строковый пул.
String s1 = "d" // строка будет сохранена в пуле
// строка не будет сохранена в пуле и будет уничтожена сборщиком мусора
String s2 = new String("a");
Один из плюсов разделения строк на статические и динамические – это повышение безопасности там, где строки используются в качестве аргументов (например, открытие баз данных, интернет соединений, механизм загрузки классов).
Операция сцепления. Для строк доступна операция +, позволяющая соединить несколько строк в одну. Если один из операндов не строка, то он автоматически преобразуется в строку. Для объектов в этих целях используется метод toString.
При каждой операции внутренне используется объект динамической строки StringBuilder или StringBuffer. Поэтому для собирания строки из нескольких все равно оптимальней использовать сразу один StringBuilder/StringBuffer.
Выделение подстроки. Есть замечание относительно метода substring – возвращаемая строка использует тот же байтовый массив, что и исходная. Например, вы загрузили строку А из файла в 1мб. Что-то там нашли и выделили в отдельную строку Б длиной в 3 символа. Строка Б в реальности тоже занимает те же 1мб.
String s ="very .... long string from file";
String sub1 = s.substring(2,4); // совместно использует ту же память что и s
String sub2 = new String(s.substring(2,4)); // этот объект использует отдельный массив на 4 символа
Основные методы. Рассмотрим основные методы String:
– equals(Object anObject) – проверяет, идентична ли строка указанному объекту;
– compareTo(String anotherString) – лексиграфическое сравнение строк;
– compareToIgnoreCase(String str) – лексиграфическое сравнение строк без учета регистра символов;
– concat(String str) – возвращает соединение двух строк;
– contains(CharSequence s) – проверяет, входит ли указанная последовательность символов в строку;
– isEmpty() – возвращает true, если длина строки равна 0;
– indexOf(String str) – поиск первого вхождения указанной подстроки;
– replace(CharSequence target, CharSequence replacement) – замена одной подстроки другой;
– substring(int beginIndex, int endIndex) – возвратить подстроку как строку;
– toLowerCase() – преобразовать строку в нижний регистр;
– toUpperCase() – преобразовать строку в верхний регистр;
– trim() – отсечь на концах строки пустые символы;
– length() – определение длины строки;
– valueOf(a) – статические методы преобразования различных типов в строку;
– charAt(int index) – возвращает символ по указанному индексу;
– regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) – тест на идентичность участков строк, можно указать учет регистра символов;
– regionMatches(int toffset, String other, int ooffset, int len) – тест на идентичность участков строк;
– endsWith(String suffix) – проверяет, завершается ли строка указанным суффиксом;
– startsWith(String prefix) – проверяет, начинается ли строка с указанного префикса;
– startsWith(String prefix, int toffset) – проверяет, начинается ли строка в указанной позиции с указанного префикса;
– getBytes() – возвращает байтовое представление строки;
– getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) – возвращает символьное представление участка строки;
– hashCode() – хеш код строки;
– indexOf(int ch) – поиск первого вхождения символа в строке;
– indexOf(int ch, int fromIndex) – поиск первого вхождения символа в строке с указанной позиции;
– indexOf(String str, int fromIndex) – поиск первого вхождения указанной подстроки с указанной позиции;
– lastIndexOf(int ch) – поиск последнего вхождения символа;
– lastIndexOf(int ch, int fromIndex) – поиск последнего вхождения символа с указанной позиции;
– lastIndexOf(String str) – поиск последнего вхождения строки;
– lastIndexOf(String str, int fromIndex) – поиск последнего вхождения строки с указанной позиции;
– replace(char oldChar, char newChar) – замена в строке одного символа на другой;
– toUpperCase(Locale locale) – преобразовать строку в верхний регистр, используя указанную локализацию;
– toLowerCase(Locale locale) – преобразовать строку в нижний регистр, используя указанную локализацию;
Методы поиска возвращают индекс вхождения или -1, если искомое не найдено. Методы преобразования (как replace) не изменяют саму строку, а возвращают соответствующий новый объект строки.
Особенности String. Неправильное использование типа String приводит к засорению оперативной памяти и как следствие к медленной работе программы. Рассмотрим пример:
public static void main(String[] args) {
String s = "a";
for (int i = 0; i < 100; i++) {
s += 'a';
}
System.out.println(s); // Распечатается строка из 100 символов «a»
}
Этот код создаст 100 разных строк, которые будут храниться в памяти, пока сборщик мусора Java не удалит их после завершения программы. В результате работы программы переменная «s» будет содержать строку из 100 символов «a», но 99 ранее созданных строк остались «мусором» в памяти без возможности обращения к ним.
Поэтому для изменения строки следует использовать класс обертку StringBuilder. Предыдущий пример нужно переписать следующим образом:
public static void main(String[] args) {
StringBuilder s = new StringBuilder("a");
for (int i = 0; i < 100; i++) {
s.append('a');
}
System.out.println(s); // Распечатается строка из 100 символов «a»
}
Динамические строки. Динамические строки описываются классами StringBuilder и StringBuffer. StringBuffer более медленный, но потокобезопасный. Переменные типа динамических строк могут менять свои значения и длину во время выполнения программы.
Основные методы динамических строк:
– append(A) – преобразовать A в строку и добавить в конец;
– insert(int offset, A) – преобразовать A в строку и вставить ее в указанную позицию;
– delete(int start, int end) – удалить символы с указанной начальной позиции по указанную конечную позицию;
– reverse() – расположить символы в обратном порядке;
– setCharAt(int index, char ch) – заменить символ в указанной позиции;
– setLength(int newLength) – установить новый размер строки;
– substring(int start) – вернуть подстроку с указанной позиции и до конца как строку;
– substring(int start, int end) – вернуть подстроку как строку;
– deleteCharAt(int index) – удалить символ в указанной позиции;
– getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) – сохранить последовательность символов в массив;
– indexOf(String str) – поиск первого вхождения подстроки;
– indexOf(String str, int fromIndex) – поиск первого вхождения подстроки с указанной позиции;
– lastIndexOf(String str) – поиск последнего вхождения подстроки;
– lastIndexOf(String str, int fromIndex) – поиск последнего вхождения подстроки с указанной позиции;
– replace(int start, int end, String str) – замена участка строки указанной строкой.
Пример преобразования строк. В этом примере массив символов и целое число преобразуются в объекты типа String с использованием методов этого класса:
package tsn01.string;
public class TSN01_String {
public static void main(String[] args) {
char s[] = {'J', 'a', 'v', 'a'}; // Массив символов
String str = new String(s); // str="Java"
if (!str.isEmpty()) {
int i = str.length(); // i=4
str = str.toUpperCase(); // str="JAVA"
String num = String.valueOf(6); // num="6"
num = str.concat("-" + num); // num="JAVA-6"
char ch = str.charAt(2); // ch='V'
i = str.lastIndexOf('A'); // i=3 (-1 если нет)
num = num.replace("6", "SE"); // num="JAVA-SE"
str.substring(0, 4).toLowerCase(); // java
str = num + "-6";// str="JAVA-SE-6"
String[] arr = str.split("-");
for (String ss : arr) { // В результате будет выведен массив строк (в 3 строчки): JAVA SE 6
System.out.println(ss);
}
} else { System.out.println("String is empty!"); }
}
}
Пример сравнение строк. В этом примере рассмотрены особенности хранения и идентификации объектов на примере вызова метода equals(), сравнивающего строку String с указанным объектом и метода hashCode(), который вычисляет хэш-код объекта (hashCode – это цифра, которая формируется для объекта по какому то правилу, например для объекта класса String по такой формуле: s[0]*31^(n-1) s[1]*31^(n-2) … s[n-1]):
package tsn01.string;
public class TSN01_String {
public static void main(String[] args) {
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
System.out.println(s1 + "==" + s2 + " : " + (s1 == s2)); // true
System.out.println(s1 + "==" + s3 + " : " + (s1 == s3)); // false
System.out.println(s1 + " equals " + s2 + " : " + s1.equals(s2)); // true
System.out.println(s1 + " equals " + s3 + " : " + s1.equals(s3)); // true
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
}
}
В результате на экран будет выведено:
Java==Java : true
Java==Java : false
Java equals Java : true
Java equals Java : true
2301506
2301506
2301506
Пример сортировки массива строк методом перебора:
package tsn01.string;
public class TSN01_String {
public static void main(String[] args) {
String a[] = {" Alena", "Alice ", " alina", " albina", " Anastasya",
" ALLA ", "AnnA "}; // Массив строк
for (int j = 0; j < a.length; j++) { // Цикл по массиву строк
// Удаляем пробелы с концов строк и приводим к верхнему регистру
a[j] = a[j].trim().toLowerCase();
}
// Сортировка строк методом пузырька
for (int j = 0; j < a.length – 1; j++) { // Цикл по массиву строк
for (int i = j + 1; i < a.length; i++) { // Цикл по массиву строк
if (a[i].compareTo(a[j]) < 0) { // Сравнение строк
String temp = a[j]; a[j] = a[i]; a[i] = temp; // Обмен значений в массиве строк
}
}
}
int i = -1;
while (++i < a.length) { System.out.print(a[i] + " "); } // Вывод массива строк на экран
}
}
В результате на экран будет выведено:
albina alena alice alina alla anastasya anna
Вызов метода trim() обеспечивает удаление всех начальных и конечных символов пробелов. Метод compareTo() выполняет лексикографическое сравнение строк между собой по правилам Unicode.
Пример работы с динамическими строками. Рассмотрим пример преобразования переменной типа «StringBuilder» к «String» через метод toString:
package tsn01.string;
public class TSN01_String {
public static void main(String[] args) {
StringBuilder s = new StringBuilder("abcd");
s.append('e');//abcde
s.delete(1, 2);//acde
s.insert(1, 'b');//abcde
s.deleteCharAt(2);//abde
String ans = s.toString();
System.out.println(ans); // На экран выведется "abde"
}
}