JavaRush /Курсы /Java Syntax Pro /Вспомогательные классы для работы со строками в Java

Вспомогательные классы для работы со строками в Java

Java Syntax Pro
9 уровень , 5 лекция
Открыта

1. Класс StringTokenizer

И еще несколько самых частых сценариев работы со строками. Как разбить строку на несколько частей? Для этого есть несколько способов.

Метод split()

Первый способ разбить строку на несколько частей — использовать метод split(). В него в качестве параметра нужно передать регулярное выражение: специальный шаблон строки-разделителя. Что такое регулярное выражение, вы узнаете в квесте Java Multithreading.

Пример:

Код Результат
String str = "Good news everyone!";
String[] strings = str.split("ne");
System.out.println(Arrays.toString(strings));
Результатом будет массив из трех строк:
["Good ", "ws everyo", "!"]

Просто, но иногда такой подход избыточен. Если разделителей много, например, «пробел», «enter», «таб», «точка», приходится конструировать достаточно сложное регулярное выражение. Его сложно читать, а значит, в него сложно вносить изменения.

Класс StringTokenizer

В Java есть специальный класс, вся работа которого — разделять строку на подстроки.

Этот класс не использует регулярные выражения: вместо этого в него просто передается строка, состоящая из символов-разделителей. Преимущества этого подхода в том, что он не разбивает сразу всю строку на кусочки, а потихоньку идет от начала к концу.

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

Методы Описание
String nextToken()
Возвращает следующую подстроку
boolean hasMoreTokens()
Проверяет, есть ли еще подстроки.

Этот класс чем-то напоминает класс Scanner, у которого тоже были методы nextLine() и hasNextLine().

Создать объект StringTokenizer можно командой:

StringTokenizer имя = new StringTokenizer(строка, разделители);

Где строка — это строка, которую будем делить на части. А разделители — это строка, каждый символ которой считается символом-разделителем. Пример:

Код Вывод на экран
String str = "Good news everyone!";

StringTokenizer tokenizer = new StringTokenizer(str,"ne");
while (tokenizer.hasMoreTokens())
{
   String token = tokenizer.nextToken();
   System.out.println(token);
}
Good 
ws 
v
ryo
!

Обратите внимание, что разделителем считается каждый символ строки, переданный второй строкой в конструктор StringTokenizer.



2. Метод String.format() и класс StringFormatter

И еще один интересный метод класса String — format().

Допустим, у вас есть различные переменные с данными. Как вывести их на экран одной строкой? Например, у нас есть данные (левая колонка) и желаемый вывод (правая колонка):

Код Вывод на экран
String name = "Amigo";
int age = 12;
String friend = "Diego";
int weight = 200;
User = {name: Amigo, age: 12 years, friend: Diego, weight: 200 kg.}

Скорее всего, ваш код будет выглядеть примерно так:

Код программы
String name = "Amigo";
int age = 12;
String friend = "Diego";
int weight = 200;

System.out.println("User = {name: " + name + ", age:" + age + " years, friend: " + friend+", weight: " + weight + " kg.}");

Такой код не слишком читабельный. Более того, если бы имена переменных были длиннее, код стал бы еще сложнее:

Код программы

class User {
    ......
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public List<String> getFriends() {
        return friends;
    }

    public ExtraInformation getExtraInformation() {
        return extraInformation;
    }
}

User user = new User();

System.out.println("User = {name: " + user.getName() + ", age:" + user.getAge() + " years, friend: " + user.getFriends().get(0) + ", weight: " + user.getExtraInformation().getWeight() + " kg.}");

Не очень читаемо, не так ли?

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

String.format

У класса String есть статический метод format(): он позволяет задать шаблон объединения строки с данными. Общий вид этой команды такой:

String имя = String.format(шаблон, параметры);

Пример:

Код Результат
String.format("Age=%d, Name=%s", age, name);
Age=12, Name=Amigo
String.format("Width=%d, Height=%d", width, height);
Width=20, Height=10
String.format("Fullname=%s", name);
Fullname=Diego

В метод format() первым параметром передают строку-шаблон, которая содержит весь нужный текст, а в местах, где нужно вставлять данные, написаны специальные символы типа %d, %s и т.п.

Вот эти %s и %d метод format() и заменяют на параметры, которые идут следом за строкой-шаблоном. Если нужно подставить строку, мы пишем %s, если число — %d. Пример:

Код Результат
String s = String.format("a=%d, b=%d, c=%d", 1, 4, 3);
s будет равна "a=1, b=4, c=3"

Вот краткий список параметров, которые можно использовать внутри шаблона:

Символ Обозначение
%s
String
%d
целое число: byte, short, int, long
%f
вещественное число: float, double
%b
boolean
%c
char
%t
Date
%%
Символ %

Эти параметры указывают на тип данных, но есть еще параметры, которые указывают на порядок данных. Чтобы взять параметр по его номеру (нумерация начинается с единицы), нужно записать %1$d вместо %d. Пример:

Код Результат
String s = String.format("a=%3$d, b=%2$d, c=%d", 11, 12, 13);
s будет равна "a=13, b=12, c=11"

%3$d возьмет 3-й параметр-переменную, %2$d возьмет второй параметр. %d возьмет самый первый параметр-переменную. Параметры шаблона %s, %d обращаются к переменным-параметрам независимо от параметров шаблона типа %3$d или %2$s



3. String Pool

Все строки, которые были заданы в коде в виде литералов, во время работы программы хранятся в памяти в так называемом StringPool. StringPool — это специальный массив для хранения строк. Цель его создания — оптимизация хранения строк:

Во-первых, строки, заданные в коде, нужно все-таки где-то хранить. Код — это команды, а данные (тем более такие большие как строки) нужно хранить в памяти отдельно от кода. В коде фигурируют только ссылки на объекты-строки.

Во-вторых, все одинаковые литералы можно хранить в памяти только один раз. Так оно и работает. Когда код вашего класса загружается Java-машиной, все строковые литералы добавляются в StringPool, если их там еще нет. Если уже есть, просто используется ссылка на строку из StringPool.

Поэтому если в своем коде вы присвоите нескольким String-переменным одинаковые литералы, переменные будут содержать одинаковые ссылки. В StringPool литерал будет добавлен только один раз, во всех остальных случаях будет браться ссылка на уже загруженную в StringPool строку.

Как это примерно работает:

Код Работа с StringPool
String a = "Привет";
String b = "Привет";
String c = "Пока";
String[] pool = {"Привет", "Пока"};
a = pool[0];
b = pool[0];
c = pool[1];

Именно поэтому переменные a и b будут хранить одинаковые ссылки.

Метод intern()

Ну и самое интересное: вы можете программно добавить любую строку в StringPool. Для этого нужно просто вызвать метод intern() у String-переменной.

Метод intern() добавит строку в StringPool, если ее еще там нет, и вернет ссылку на строку из StringPool.

Если в StringPool добавить с помощью метода intern() две идентичные строки, метод вернет одинаковые ссылки. Это можно использовать чтобы сравнивать строки по ссылке. Пример:

Код Примечание
String a = new String("Привет");
String b = new String("Привет");
System.out.println(a == b);


false
String a = new String("Привет");
String b = new String("Привет");

String t1 = a.intern();
String t2 = b.intern();
System.out.println(a == b);
System.out.println(t1 == t2);





false
true

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


Комментарии (439)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
C0N5P1RACY Уровень 21
9 декабря 2025
Лучше знать, чем не знать :)
Grigoryvvv Уровень 14 Expert
18 ноября 2025
18.11.2025 / 10 уровень
Семен Уровень 13
12 ноября 2025
public class Solution { public static void main(String[] args) { String packagePath = "java.util.stream"; String[] tokens = getTokens(packagePath, "\\."); System.out.println(Arrays.toString(tokens)); } public static String[] getTokens(String query, String delimiter) { //напишите тут ваш код //напишите тут ваш код StringTokenizer token = new StringTokenizer(query, "\\."); int index = token.countTokens(); String [] tokens = new String[index]; for (int i = 0; i < index; i++) { tokens[i] = "\"" + token.nextToken() + "\""; } return tokens; } } Выводит: ["java", "util", "stream"] Задачу не принимает.
FosTeR Уровень 16
12 ноября 2025
StringTokenizer token = new StringTokenizer(query, "\\."); второе значение у тебя скажем константа, а должно быть плавающее(мало ли какой разделитель пользователь захочет) Если вдруг не понятно объяснил то: StringTokenizer token = new StringTokenizer(query, delimiter); 1)зачем тебе кавычки при записи? 2)зачем отдельно int index создавать?зачем тебе лишняя строка? когда for смотрю, то ищу что за индекс и чему он равен, а массив.длина=>сразу понятно.
Кирилл Уровень 38
20 октября 2025
мож я дурак, но сработало //напишите тут ваш код String t1 = first.intern(); String t2 = second.intern(); return t1 == t2;
Pukidmi Уровень 7
27 октября 2025
Это правильно решение, но можно и без переменных обойтись.
Кирилл Уровень 38
31 октября 2025
я слишком тупой для программирования, спасибо что хотябы так чёт получилось
Pukidmi Уровень 7
31 октября 2025
Глупости не говори, ты молодец
FosTeR Уровень 16
12 ноября 2025
Дружище ты не дурак, ты учишься. сначала интуинтивно=>потом осознал=> в будущем вспомнил и уже сразу сделал. 👍👍👍
Elisbeth Уровень 17
20 сентября 2025
Я чёт не поняла, а название пункта 2 про класс StringFormatter по приколу вставили? Где хоть слово про этот класс???
Anton Zorin Уровень 20
20 августа 2025
StringTokenizer — это устаревший (legacy) класс, сохраненный для обратной совместимости. Для нового кода настоятельно рекомендуется использовать String.split() или java.util.regex.Package, так как они более мощные и предсказуемые.
14 августа 2025
Жесть, боюсь заглядывать в задачи, там наверное тёмный ужас....
VAKHANDER Уровень 32
30 июля 2025
Ребят, пишу отчет-совет, проходите курс до примерно 30 уровня, затем желательно пройти бесплатный курс на stepik по sql, затем покопаться в spring-boot + hiber/jdbc и можно проходить собесы. Ровно 11 месяцев занял мой путь изучения с 0 и до трудоустройства. Кому интересно узнать больше о работе с точки зрения джуна вот мой тг-канал: https://t.me/javafrom0toTeamLead
invoker main Уровень 42
14 сентября 2025
можешь дать свой тг? оч интересно кое что уточнить
Anonymous #3585174 Уровень 33
19 июня 2025
like
Alina Gabidulina Уровень 27
8 мая 2025
Ничего не понятно, почему a==b это фолс, а t1==t2 это тру?Не понимаю что делает интерн какую ссылку он возвращает

System.out.println(a == b);
System.out.println(t1 == t2);
это код что сравнивает?по содержанию или по ссылкам?
Sergei Уровень 20
9 мая 2025
Когда мы инициализируем b, мы создаем новую ссылку, на тот же объект. А когда мы вызываем ссылку через метод .intern(), нам из StringPool(хранилища строк(объектов строк))по сути выдают одну и туже ссылку, и переменные t1 и t2 имеют одну ссылку на один и то же объект.
Виктор Уровень 25
12 мая 2025
new создаёт новый обьект класса String вне хранилища string pool. Раньше был пример с этим вроде.
FosTeR Уровень 16
12 ноября 2025
а == b -сравнение ссылок t1 == t2 сравнение содержимого ссылок( ps( equal это тоже сравнение содержимого ссылок)) Я по такой аналогии эту тему выучил🤪