Класс String
Этот класс представляет собой последовательность символов. Все определенные в программ строковые литералы, вроде "This is String" — это экземпляры класса String. У String есть две фундаментальные особенности:- это immutable (неизменный) класс
- это final класс
final
) и экземпляры класса нельзя изменить после создания (immutable
). Это дает классу String несколько важных преимуществ:
-
Благодаря неизменности, хэшcode экземпляра класса String кэшируется. Его не нужно вычислять каждый раз, потому что значения полей an object никогда не изменятся после его создания. Это дает высокую производительность при использовании данного класса в качестве ключа для
HashMap
. -
Класс String можно использовать в многопоточной среде без дополнительной синхронизации.
-
Еще одна особенность класса String — для него перегружен оператор "
+
" в Java. Поэтому конкатенация (сложение) строк выполняется довольно просто:
public static void main(String[] args) {
String command = "Follow" + " " + "the" + " " + "white" + " " + "rabbit";
System.out.println(command); // Follow the white rabbit
}
Под капотом конкатенация строк выполняется классом StringBuilder либо StringBuffer (на усмотрение компилятора) и методом append
(об этих классах поговорим чуть позже). Если мы будем складывать экземпляры класса String с экземплярами других классов, последние будут приводиться к строковому представлению:
public static void main(String[] args) {
Boolean b = Boolean.TRUE;
String result = "b is " + b;
System.out.println(result); //b is true
}
Это еще одно интересное свойство класса String: an objectы любых классов можно привести к строковому представлению, используя метод toString()
, определенный в классе Object
и наследуемый всеми остальными классами. Часто метод toString() у an object вызывается неявно. Например когда мы выводим что-то на экран or складываем String с an objectом другого класса. У класса String есть еще одна особенность. Все строковые литералы, определенные в Java codeе, вроде "asdf", на этапе компиляции кэшируются и добавляются в так называемый пул строк. Если мы запустим следующий code:
String a = "Wake up, Neo";
String b = "Wake up, Neo";
System.out.println(a == b);
Мы увидим в консоли true, потому что переменные a
и b
в действительности будут ссылаться на один и тот же экземпляр класса String, добавленный в пул строк на этапе компиляции. То есть, разные экземпляры класса с одинаковым meaningм не создаются, и память экономится.
Недостатки:
Нетрудно догадаться, что класс String нужен в первую очередь для работы со строками. Но в некоторых случаях перечисленные выше особенности класса String могут превратиться из достоинств в недостатки. После создания строк в codeе Java-программы с ними часто совершается множество операций:- перевод строк в разные регистры;
- извлечение подстрок;
- конкатенация;
- и т.д.
public static void main(String[] args) {
String s = " Wake up, Neo! ";
s = s.toUpperCase();
s = s.trim();
System.out.println("\"" + s + "\"");
}
С первого взгляда кажется, что мы всего-то перевели строку "Wake up, Neo!" в верхний регистр, удалor из данной строки лишние пробелы и обернули в кавычки. На самом деле, в силу неизменности класса String, в результате каждой операции создаются новые экземпляры строк, а старые отбрасываются, порождая большое количество мусора. Как же избежать нерационального использования памяти?
Класс StringBuffer
Whatбы справиться с созданием временного мусора из-за модификаций an object String, можно использовать класс StringBuffer. Этоmutable
класс, т.е. изменяемый. Объект класса StringBuffer может содержать в себе определенный набор символов, длину и meaning которого можно изменить через вызов определенных методов. Посмотрим, How работает данный класс. Для создания нового an object используется один из его конструкторов, например:
- StringBuffer() — создаст пустой (не содержащий символов) an object
- StringBuffer(String str) — создаст an object на основе переменной str (содержащий все символы str в той же последовательности)
StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Not empty");
Конкатенация строк через StringBuffer в Java выполняется с помощью метода append
. Вообще метод append
в классе StringBuffer перегружен таким образом, что может принимать в себя практически любой тип данных:
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
sb.append(new Integer(2));
sb.append("; ");
sb.append(false);
sb.append("; ");
sb.append(Arrays.asList(1,2,3));
sb.append("; ");
System.out.println(sb); // 2; false; [1, 2, 3];
}
Метод append
возвращает an object, на котором был вызван (How и многие другие методы), что позволяет вызывать его “цепочкой”. Пример выше можно написать так:
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
sb.append(new Integer(2))
.append("; ")
.append(false)
.append("; ")
.append(Arrays.asList(1,2,3))
.append("; ");
System.out.println(sb); // 2; false; [1, 2, 3];
}
Для работы со строками у класса StringBuffer есть ряд методов. Перечислим основные:
delete(int start, int end)
— удаляет подстроку символов начиная с позицииstart
, заканчиваяend
deleteCharAt(int index)
— удаляет символ в позицииindex
insert(int offset, String str)
— вставляет строкуstr
в позициюoffset
. Методinsert
также перегружен и может принимать различные аргументыreplace(int start, int end, String str)
— заменит все символы начиная с позицииstart
до позицииend
наstr
reverse()
— меняет порядок всех символов на противоположныйsubstring(int start, int end)
— вернет подстроку, начиная с позицииstart
до позицииend
substring(int start)
— вернет подстроку, начиная с позиции
start
public static void main(String[] args) {
String numbers = "0123456789";
StringBuffer sb = new StringBuffer(numbers);
System.out.println(sb.substring(3)); // 3456789
System.out.println(sb.substring(4, 8)); // 4567
System.out.println(sb.replace(3, 5, "ABCDE")); // 012ABCDE56789
sb = new StringBuffer(numbers);
System.out.println(sb.reverse()); // 9876543210
sb.reverse(); // Return the original order
sb = new StringBuffer(numbers);
System.out.println(sb.delete(5, 9)); // 012349
System.out.println(sb.deleteCharAt(1)); // 02349
System.out.println(sb.insert(1, "One")); // 0One2349
}
Преимущества:
-
Как уже сказано, StringBuffer — изменяемый класс, поэтому при работе с ним не возникает такого же количества мусора в памяти, How со String. Поэтому если над строками проводится много модификаций, лучше использовать
StringBuffer
. -
StringBuffer — потокобезопасный класс. Его методы синхронизированы, а экземпляры могут быть использованы несколькими потоками одновременно.
Недостатки:
С одной стороны, потокобезопасность — преимущество класса, а другой — недостаток. Синхронизированные методы работают медленнее не сихнронизированных. И здесь в игру вступает StringBuilder. Давайте разберемся, что это за класс Java — StringBuilder, Howие методы есть и в чем его особенности.Класс StringBuilder
StringBuilder в Java — класс, представляющий последовательность символов. Он очень похож на StringBuffer во всем, кроме потокобезопасности. StringBuilder предоставляет API, аналогичный API StringBuffer’a. Продемонстрируем это на уже знакомом примере, заменив объявление переменных со StringBufer’а на StringBuilder:
public static void main(String[] args) {
String numbers = "0123456789";
StringBuilder sb = new StringBuilder(numbers);
System.out.println(sb.substring(3)); //3456789
System.out.println(sb.substring(4, 8)); //4567
System.out.println(sb.replace(3, 5, "ABCDE")); //012ABCDE56789
sb = new StringBuilder(numbers);
System.out.println(sb.reverse()); //9876543210
sb.reverse(); // Return the original order
sb = new StringBuilder(numbers);
System.out.println(sb.delete(5, 9)); //012349
System.out.println(sb.deleteCharAt(1)); //02349
System.out.println(sb.insert(1, "One")); //0One2349
}
Difference лишь в том, что StringBuffer потокобезопасен, и все его методы синхронизированы, а StringBuilder — нет. Это единственная особенность. StringBuilder в Java работает быстрее StringBuffer’а благодаря несинхронизированности методов. Поэтому в большинстве случаев, кроме многопоточной среды, лучше использовать для программы на Java StringBuilder. Резюмируем все в сравнительной таблице трех классов:
String vs StringBuffer vs StringBuilder
String | StringBuffer | StringBuilder | |
---|---|---|---|
Изменяемость | Immutable (нет) |
mutable (да) |
mutable (да) |
Расширяемость | final (нет) |
final (нет) |
final (нет) |
Потокобезопасность | Да, за счет неизменяемости | Да, за счет синхронизации | Нет |
Когда использовать | При работе со строками, которые редко будут модифицироваться | При работе со строками, которые часто будут модифицироваться в многопоточной среде | При работе со строками, которые часто будут модифицироваться, в однопоточной среде |
GO TO FULL VERSION