Класс
String в Java представляет строку, то есть последовательность символов. Все строковые литералы, определенные в Java-программе (например, "abc"), это экземпляры класса String.
Кратко
- Строки создают литералом в двойных кавычках. Конструктор
new String() нужен в редких случаях. - Одинаковые литералы Java хранит в String Pool и переиспользует, поэтому
== для них дает true. Для строк, созданных через new, тот же == даст false. - Сравнивать строки по содержимому нужно методом
equals(), а без учета регистра методом equalsIgnoreCase(). - Любой объект и примитив переводится в строку методом
String.valueOf(), а строка в число методами parseInt(), parseDouble() и другими parse... у классов-оберток. String.join() собирает коллекцию в одну строку, а split() разбивает строку на массив по регулярному выражению.- Из современного: с Java 9 работают Compact Strings, с Java 11 есть
isBlank(), strip(), repeat() и lines(), с Java 15 текстовые блоки и formatted().
Давай посмотрим на его ключевые характеристики:
- Класс реализует интерфейсы
Serializable и CharSequence. Поскольку он входит в пакет java.lang, его не нужно импортировать.
- Класс String в Java это final класс, который не может иметь потомков.
- Класс String это immutable класс, то есть его объекты не могут быть изменены после создания. Любые операции над объектом String, результатом которых должен быть объект класса String, приведут к созданию нового объекта.
- Благодаря своей неизменности, объекты класса String являются потокобезопасными и могут быть использованы в многопоточной среде.
- Каждый объект в Java может быть преобразован в строку через метод
toString, унаследованный всеми Java-классами от класса Object.
![Черно-белое фото страницы с рукописным текстом и зачеркнутыми словами]()
Работа с Java String
Это один из самых часто используемых классов в Java. В нем есть методы для анализа определенных символов строки, для сравнения и поиска строк, извлечения подстрок, создания копии строки с переводом всех символов в нижний и верхний регистр и прочие. Список всех методов класса String можно изучить в
официальной документации.
Также в Java реализован несложный механизм конкатенации (соединения строк), преобразования примитивов в строку и наоборот.
Давай рассмотрим некоторые примеры работы с классом String в Java.
Создание строк
Проще всего создать экземпляр класса String, присвоив ему значение строкового литерала:
String s = "I love movies";
Однако у класса String есть много
конструкторов, которые позволяют:
- создать объект, содержащий пустую строку
- создать копию строковой переменной
- создать строку на основе массива символов
- создать строку на основе массива байтов (с учетом кодировок)
- и т.д.
String Pool и интернирование строк
Теперь давай разберемся, что происходит в памяти, когда мы создаем строки разными способами. Это поможет тебе понимать, как Java оптимизирует работу со строками и почему иногда важен способ их создания.
Что такое String Pool?
String Pool (пул строк) это специальная область памяти в Java, где хранятся строковые литералы. Когда ты создаешь строку с помощью литерала, Java сначала проверяет: есть ли уже такая строка в пуле? Если да, просто возвращает ссылку на существующий объект. Если нет, создает новый и помещает его в пул.
Это экономит память, ведь одинаковые строки не дублируются!
Практический пример:
public static void main(String[] args) {
String a = "JavaRush";
String b = "JavaRush";
System.out.println(a == b);
System.out.println(a.equals(b));
}
Почему a == b возвращает true?
Потому что обе переменные ссылаются на один и тот же объект в String Pool. Java увидела, что строка "JavaRush" уже существует в пуле, и просто вернула ссылку на нее.
А что с конструктором?
Когда ты создаешь строку через конструктор new String(), Java всегда создает новый объект в памяти (в heap), даже если такая строка уже есть в пуле:
public static void main(String[] args) {
String c = new String("JavaRush");
String d = new String("JavaRush");
System.out.println(c == d);
System.out.println(c.equals(d));
}
Почему c == d возвращает false?
Потому что c и d ссылаются на два разных объекта в памяти, хотя содержат одинаковый текст. Оператор == сравнивает ссылки (адреса в памяти), а метод equals() сравнивает содержимое строк.
Метод intern(): принудительное интернирование
Если ты создал строку через конструктор, но хочешь поместить ее в String Pool, используй метод intern():
public static void main(String[] args) {
String e = new String("JavaRush").intern();
String f = new String("JavaRush").intern();
System.out.println(e == f);
System.out.println(e.equals(f));
}
Метод intern() проверяет: есть ли такая строка в пуле? Если да, возвращает ссылку на нее. Если нет, добавляет в пул и возвращает ссылку.
Литералы vs конструктор: что выбрать?
Когда использовать литералы?
В 99% случаев используй литералы (двойные кавычки):
String name = "Alex";
Почему?
- Экономит память (благодаря String Pool)
- Быстрее работает
- Проще и понятнее код
- Это стандартная практика в Java
Когда использовать конструктор?
Конструктор
new String() нужен очень редко, только если тебе действительно нужен новый объект в памяти. Например:
String userInput = getUserInput();
String safeString = new String(userInput.substring(0, 10));
Но даже такие случаи встречаются крайне редко.
Запомни правило: всегда используй литералы, если нет веской причины делать иначе.
❌ Типичная ошибка новичков:
String s = new String("Hello");
В этом коде создается два объекта:
- Литерал "Hello" в String Pool
- Новый объект в heap через конструктор
Правильно:
String s = "Hello";
Сложение строк
Сложить две строки в Java довольно просто, воспользовавшись оператором
+. Java позволяет складывать друг с другом и переменные, и строковые литералы:
public static void main(String[] args) {
String day = "День";
String and = "и";
String night = "Ночь";
String dayAndNight = day + " " + and + " " + night;
}
Складывая объекты класса String с объектами других классов, мы приводим последние к строковому виду. Преобразование объектов других классов к строковому представлению выполняется через неявный вызов метода
toString у объекта. Продемонстрируем это на следующем примере:
public class StringExamples {
public static void main(String[] args) {
Human max = new Human("Макс");
String out = "Java объект: " + max;
System.out.println(out);
}
static class Human {
private String name;
public Human(String name) {
this.name = name;
}
@Override
public String toString() {
return "Человек с именем " + name;
}
}
}
Сравнение строк
Для
сравнения строк можно воспользоваться методом
equals():
public static void main(String[] args) {
String x = "Test String";
System.out.println("Test String".equals(x));
}
Когда при сравнении строк нам не важен регистр, нужно использовать метод
equalsIgnoreCase():
public static void main(String[] args) {
String x = "Test String";
System.out.println("test string".equalsIgnoreCase(x));
}
Перевод объекта/примитива в строку
Для перевода экземпляра любого Java-класса или любого примитивного типа данных к строковому представлению, можно использовать метод
String.valueOf():
public class StringExamples {
public static void main(String[] args) {
String a = String.valueOf(1);
String b = String.valueOf(12.0D);
String c = String.valueOf(123.4F);
String d = String.valueOf(123456L);
String s = String.valueOf(true);
String human = String.valueOf(new Human("Alex"));
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(s);
System.out.println(human);
}
static class Human {
private String name;
public Human(String name) {
this.name = name;
}
@Override
public String toString() {
return "Человек с именем " + name;
}
}
}
Перевод строки в число
Часто бывает нужно перевести строку в число. У классов оберток примитивных типов есть методы, которые служат как раз для этой цели. Все эти методы начинаются со слова parse. Рассмотрим ниже перевод строки в целочисленное (
Integer) и дробное (
Double) числа:
public static void main(String[] args) {
Integer i = Integer.parseInt("12");
Double d = Double.parseDouble("12.65D");
System.out.println(i);
System.out.println(d);
}
Перевод коллекции строк к строковому представлению
Если нужно преобразовать все элементы некоторой коллекции строк к строковому представлению через произвольный разделитель, можно использовать такие методы класса String Java:
join(CharSequence delimiter, CharSequence... elements)
join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
Где
delimiter это разделитель элементов, а
elements это массив строк / экземпляр коллекции строк.
Рассмотрим пример, в котором мы преобразуем список строк в строку, разделяя каждую точкой с запятой:
public static void main(String[] args) {
List<String> people = Arrays.asList(
"Philip J. Fry",
"Turanga Leela",
"Bender Bending Rodriguez",
"Hubert Farnsworth",
"Hermes Conrad",
"John D. Zoidberg",
"Amy Wong"
);
String peopleString = String.join("; ", people);
System.out.println(peopleString);
}
Разбиение строки на массив строк
Эту операцию выполняет метод
split(String regex)
В качестве разделителя выступает строковое
регулярное выражение regex.
В примере ниже произведем операцию, обратную той, что мы выполняли в предыдущем примере:
public static void main(String[] args) {
String people = "Philip J. Fry; Turanga Leela; Bender Bending Rodriguez; Hubert Farnsworth; Hermes Conrad; John D. Zoidberg; Amy Wong";
String[] peopleArray = people.split("; ");
for (String human : peopleArray) {
System.out.println(human);
}
}
Определение позиции элемента в строке
В языке Java String предоставляет набор методов для определения позиции символа/подстроки в строке:
indexOf(int ch)
indexOf(int ch, int fromIndex)
indexOf(String str)
indexOf(String str, int fromIndex)
lastIndexOf(int ch)
lastIndexOf(int ch, int fromIndex)
lastIndexOf(String str)
lastIndexOf(String str, int fromIndex)
Где:
ch это искомый символ (char)
str это искомая строка
fromIndex это позиция, с которой нужно искать элемент
- методы
indexOf возвращают позицию первого найденного элемента
- методы
lastIndexOf возвращают позицию последнего найденного элемента
Если искомый элемент не найден, методы вернут -1.
Попробуем найти порядковый номер букв
A,
K,
Z,
Я в английском алфавите, но будем иметь в виду, что индексация символов в строке в Java начинается с нуля:
public static void main(String[] args) {
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
System.out.println(alphabet.indexOf('A'));
System.out.println(alphabet.indexOf('K'));
System.out.println(alphabet.indexOf('Z'));
System.out.println(alphabet.indexOf('Я'));
}
Извлечение подстроки из строки
Для извлечения подстроки из строки класс String в Java предоставляет методы:
substring(int beginIndex)
substring(int beginIndex, int endIndex)
Рассмотрим, как с помощью методов определения позиции элемента и извлечения подстроки мы можем получить имя файла из его пути:
public static void main(String[] args) {
String filePath = "D:\\Movies\\Futurama.mp4";
int lastFileSeparatorIndex = filePath.lastIndexOf('\\');
String fileName = filePath.substring(lastFileSeparatorIndex + 1);
System.out.println(fileName);
}
Перевод строки в верхний/нижний регистр
Класс String предоставляет методы для перевода строки в верхний и нижний регистры:
toLowerCase()
toUpperCase()
Рассмотрим работу данных методов на примере:
public static void main(String[] args) {
String fry = "Philip J. Fry";
String lowerCaseFry = fry.toLowerCase();
String upperCaseFry = fry.toUpperCase();
System.out.println(lowerCaseFry);
System.out.println(upperCaseFry);
}
Новые возможности Java String
Java продолжает развиваться, и класс String получил несколько полезных дополнений в последних версиях. Давай посмотрим на самые важные из них.
Text Blocks (Java 15+)
Если тебе нужно работать с многострочным текстом, text blocks значительно упростят жизнь:
public static void main(String[] args) {
String json = "{\n" +
" \"name\": \"Philip J. Fry\",\n" +
" \"job\": \"Delivery Boy\"\n" +
"}";
String jsonNew = """
{
"name": "Philip J. Fry",
"job": "Delivery Boy"
}
""";
System.out.println(jsonNew);
}
Text blocks начинаются и заканчиваются тремя двойными кавычками
""". Все переносы строк и отступы сохраняются автоматически!
Метод formatted() (Java 15+)
Вместо сложной конкатенации теперь можно использовать удобное форматирование:
public static void main(String[] args) {
String name = "Bender";
int age = 4;
String message1 = "Привет, я " + name + " и мне " + age + " года";
String message2 = "Привет, я %s и мне %d года".formatted(name, age);
String message3 = String.format("Привет, я %s и мне %d года", name, age);
System.out.println(message2);
}
Полезные методы для проверки строк
В современной Java появились удобные методы для частых операций:
public static void main(String[] args) {
String empty = "";
String spaces = " ";
String text = "JavaRush";
System.out.println(empty.isBlank());
System.out.println(spaces.isBlank());
System.out.println(text.isBlank());
String withSpaces = " JavaRush ";
System.out.println(withSpaces.strip());
System.out.println(withSpaces.stripLeading());
System.out.println(withSpaces.stripTrailing());
System.out.println("Ha".repeat(3));
"Line1\nLine2\nLine3".lines()
.forEach(System.out::println);
}
Compact Strings - автоматическая оптимизация (Java 9+)
Начиная с Java 9, класс String стал автоматически оптимизировать память. Если строка содержит только латинские символы (Latin-1), она занимает в два раза меньше памяти!
String latin = "Hello World";
String cyrillic = "Привет Мир";
Это происходит автоматически, тебе ничего делать не нужно. Просто знай, что Java следит за эффективностью использования памяти сама!
Что появилось в String по версиям
Соберем нововведения из этого раздела в одну таблицу:
| Версия Java | Что появилось в классе String |
|---|
| Java 9 | Compact Strings: строка из латиницы занимает в памяти вдвое меньше |
| Java 11 | isBlank(), strip(), stripLeading(), stripTrailing(), repeat(), lines() |
| Java 15 | текстовые блоки на тройных кавычках и метод formatted() |
Работа с данным классом Java изучается на начальных уровнях онлайн-курса JavaRush:
Вопросы и ответы
Чем == отличается от equals() при сравнении строк?
Оператор == сравнивает ссылки, то есть проверяет, один ли это объект в памяти. Метод equals() сравнивает содержимое. Для строк, созданных через new, == вернет false даже при одинаковом тексте, поэтому сравнивать строки нужно через equals().
Что такое String Pool и зачем он нужен?
Это область памяти, где Java хранит строковые литералы. При создании строки литералом Java сначала ищет такую же в пуле и, если находит, возвращает ссылку на существующий объект. Так одинаковые строки не дублируются и экономится память.
Почему не стоит создавать строки через new String()?
Потому что создается лишний объект: сам литерал попадает в String Pool, а конструктор делает еще одну копию в heap. Литерал в двойных кавычках экономит память и работает быстрее.
Как перевести строку в число и число в строку?
Строку в число переводят методы parse у классов-оберток: Integer.parseInt для целых, Double.parseDouble для дробных. Обратно любой примитив или объект переводится методом String.valueOf().
Как разбить строку на части и собрать обратно?
Разбить помогает метод split(): он принимает регулярное выражение-разделитель и возвращает массив строк. Собрать обратно помогает статический метод String.join(): он принимает разделитель и коллекцию или массив строк.
Почему класс String сделали immutable?
Неизменяемость позволяет безопасно хранить строки в String Pool и переиспользовать один объект в разных местах программы. Она же делает строки потокобезопасными: их можно передавать между потоками, не опасаясь, что кто-то изменит значение.
Источник:
Oracle Java Tutorials: Strings.
Читайте также