Методы строк — полное руководство в Java: подробное руководство
Что это такое и зачем? (аналогия из реальной жизни)
Представь, что ты работаешь в библиотеке. У тебя есть книга — это строка текста. Но книга может быть в разных состояниях: в твёрдой обложке, с закладками, с пометками на полях. Ты можешь с книгой делать разные вещи: перелистывать страницы, искать определённое слово, заменять старые страницы на новые, вырезать кусок текста или склеивать две книги вместе.
В программировании строка (String) — это та же книга. Это последовательность символов: букв, цифр, пробелов, знаков препинания. А методы строк — это те самые действия, которые ты можешь с этой «книгой» совершать. Методы — это встроенные функции, которые уже написаны за тебя. Тебе не нужно придумывать, как найти слово в тексте или как сделать все буквы заглавными — Java уже всё умеет.
💡 Важно понять: строки в Java — это объекты. У каждого объекта есть методы. Когда ты пишешь точку после имени строки, ты говоришь: «Эй, строка, сделай что-то со своим содержимым!»
Зачем это нужно? Представь, что ты пишешь программу для проверки пароля. Тебе нужно узнать, длиннее ли он 8 символов, есть ли в нём цифры, не совпадает ли он с именем пользователя. Без методов строк тебе пришлось бы писать десятки строк кода, перебирая каждый символ вручную. С методами — это одна-две команды.
Теория: как это работает изнутри
Давай заглянем под капот. Когда ты пишешь String text = "Привет";, Java делает несколько важных вещей:
- Создаёт объект класса
Stringв специальной области памяти — куче (heap). - Запоминает массив символов внутри этого объекта. Строка — это, по сути, массив типа
char[]. Каждая буква, пробел или знак — отдельный элемент этого массива. - Фиксирует длину — количество символов в массиве.
Самая важная особенность строк в Java — они неизменяемые (immutable). Это значит, что когда ты вызываешь метод, который «меняет» строку, на самом деле создаётся новая строка. Старая остаётся нетронутой.
⚠️ Запомни раз и навсегда: String — неизменяемый тип. Любой метод, который выглядит как «изменение» строки (замена, удаление, перевод в верхний регистр), возвращает новую строку. Оригинал не меняется никогда.
Почему так сделано? Во-первых, это безопасно. Если ты передал строку в метод, ты уверен, что метод её не испортит. Во-вторых, это позволяет Java оптимизировать память: одинаковые строки могут храниться в одном месте (это называется пул строк).
Внутри класса String есть около 70 методов. Мы разберём самые важные, которые ты будешь использовать в 99% случаев.
Синтаксис в Java: все формы и варианты
Методы строк вызываются через точку. Общий синтаксис:
результат = строка.имяМетода(аргументы);
Где результат — это то, что метод возвращает (число, новую строку, логическое значение), а аргументы — данные, которые ты передаёшь методу (например, символ для поиска или новую подстроку).
Вот полная таблица самых популярных методов. Держи её под рукой — она пригодится:
| Метод | Что делает | Что возвращает | Пример |
|---|---|---|---|
length() |
Считает количество символов | int (целое число) |
"Кот".length() → 3 |
charAt(int index) |
Возвращает символ на указанной позиции | char (один символ) |
"Кот".charAt(1) → 'о' |
toUpperCase() |
Переводит все буквы в верхний регистр | String (новая строка) |
"кот".toUpperCase() → "КОТ" |
toLowerCase() |
Переводит все буквы в нижний регистр | String (новая строка) |
"Кот".toLowerCase() → "кот" |
equals(Object obj) |
Сравнивает строки по содержимому | boolean (true/false) |
"кот".equals("кот") → true |
equalsIgnoreCase(String str) |
Сравнивает строки без учёта регистра | boolean |
"Кот".equalsIgnoreCase("кот") → true |
contains(CharSequence s) |
Проверяет, содержит ли строка подстроку | boolean |
"Привет".contains("рив") → true |
startsWith(String prefix) |
Проверяет, начинается ли строка с подстроки | boolean |
"Java".startsWith("Ja") → true |
endsWith(String suffix) |
Проверяет, заканчивается ли строка на подстроку | boolean |
"Java".endsWith("va") → true |
indexOf(String str) |
Ищет первое вхождение подстроки | int (индекс или -1) |
"Кот".indexOf("т") → 2 |
lastIndexOf(String str) |
Ищет последнее вхождение подстроки | int (индекс или -1) |
"Кот".lastIndexOf("т") → 2 |
substring(int beginIndex) |
Вырезает часть строки от индекса до конца | String (новая строка) |
"Привет".substring(3) → "вет" |
substring(int begin, int end) |
Вырезает часть строки от begin до end (не включая end) | String |
"Привет".substring(0, 3) → "При" |
replace(char old, char new) |
Заменяет все вхождения одного символа на другой | String |
"Кот".replace('т', 'д') → "Код" |
replace(CharSequence target, CharSequence replacement) |
Заменяет одну подстроку на другую | String |
"Кот".replace("Ко", "Ро") → "Рот" |
trim() |
Удаляет пробелы в начале и конце строки | String |
" Кот ".trim() → "Кот" |
split(String regex) |
Разбивает строку на массив по разделителю | String[] (массив строк) |
"Кот,Пёс".split(",") → ["Кот", "Пёс"] |
isEmpty() |
Проверяет, пустая ли строка (длина 0) | boolean |
"".isEmpty() → true |
isBlank() |
Проверяет, пустая ли строка или состоит только из пробелов | boolean |
" ".isBlank() → true |
toCharArray() |
Превращает строку в массив символов | char[] |
"Кот".toCharArray() → ['К', 'о', 'т'] |
concat(String str) |
Соединяет две строки (как +) | String |
"Ко".concat("т") → "Кот" |
repeat(int count) |
Повторяет строку указанное количество раз | String |
"Ко".repeat(2) → "КоКо" |
🔑 Ключевой момент: Индексы в строках начинаются с 0. Первый символ — это индекс 0, второй — 1, и так далее. Последний символ имеет индекс length() - 1.
Примеры кода — от простого к сложному
Пример 1: Знакомство с длиной и символами
public class StringExample1 {
public static void main(String[] args) {
// Создаём строку
String greeting = "Привет, мир!";
// Узнаём длину строки
int length = greeting.length();
System.out.println("Длина строки: " + length); // Выведет: 13
// Получаем символ на позиции 0 (первый символ)
char firstChar = greeting.charAt(0);
System.out.println("Первый символ: " + firstChar); // Выведет: П
// Получаем символ на позиции 7 (восьмой символ)
char eighthChar = greeting.charAt(7);
System.out.println("Символ на позиции 7: " + eighthChar); // Выведет: м
// Важно: если запросить индекс за пределами строки, будет ошибка
// char error = greeting.charAt(100); // ❌ Ошибка! StringIndexOutOfBoundsException
}
}
Пример 2: Регистр букв и сравнение
public class StringExample2 {
public static void main(String[] args) {
String original = "Java Программирование";
// Переводим в верхний регистр
String upper = original.toUpperCase();
System.out.println("Верхний регистр: " + upper); // JAVA ПРОГРАММИРОВАНИЕ
// Переводим в нижний регистр
String lower = original.toLowerCase();
System.out.println("Нижний регистр: " + lower); // java программирование
// Сравниваем строки
String password1 = "Secret123";
String password2 = "secret123";
// equals() — строгое сравнение (регистр важен)
boolean isEqual = password1.equals(password2);
System.out.println("Строгое сравнение: " + isEqual); // false
// equalsIgnoreCase() — сравнение без учёта регистра
boolean isEqualIgnoreCase = password1.equalsIgnoreCase(password2);
System.out.println("Сравнение без регистра: " + isEqualIgnoreCase); // true
// Сравнение через == (НЕ ДЕЛАЙ ТАК!)
String a = "Привет";
String b = "Привет";
String c = new String("Привет");
System.out.println(a == b); // true (но это случайность, из-за пула строк)
System.out.println(a == c); // false (разные объекты в памяти)
System.out.println(a.equals(c)); // true (правильное сравнение)
}
}
⚠️ Ошибка новичков: Никогда не используй==для сравнения строк!==сравнивает ссылки (адреса в памяти), а не содержимое. Всегда используйequals().
Пример 3: Поиск подстрок и проверка содержимого
public class StringExample3 {
public static void main(String[] args) {
String text = "Я люблю программировать на Java";
// Проверяем, содержит ли строка подстроку
boolean containsJava = text.contains("Java");
System.out.println("Содержит 'Java': " + containsJava); // true
// Проверяем начало и конец строки
boolean startsWith = text.startsWith("Я люблю");
System.out.println("Начинается с 'Я люблю': " + startsWith); // true
boolean endsWith = text.endsWith("Java");
System.out.println("Заканчивается на 'Java': " + endsWith); // true
// Ищем позицию подстроки
int indexOfJava = text.indexOf("Java");
System.out.println("Позиция 'Java': " + indexOfJava); // 28
// Если подстрока не найдена, возвращается -1
int indexOfPython = text.indexOf("Python");
System.out.println("Позиция 'Python': " + indexOfPython); // -1
// Ищем последнее вхождение
String repeated = "кот кот кот";
int lastIndex = repeated.lastIndexOf("кот");
System.out.println("Последнее 'кот' на позиции: " + lastIndex); // 8
}
}
Пример 4: Извлечение частей строки
public class StringExample4 {
public static void main(String[] args) {
String fullName = "Иванов Иван Иванович";
// Извлекаем фамилию (первые 6 символов)
String lastName = fullName.substring(0, 6);
System.out.println("Фамилия: " + lastName); // Иванов
// Извлекаем имя (с 7-го символа до конца)
// Сначала найдём пробел после фамилии
int firstSpace = fullName.indexOf(' ');
int secondSpace = fullName.indexOf(' ', firstSpace + 1);
String firstName = fullName.substring(firstSpace + 1, secondSpace);
System.out.println("Имя: " + firstName); // Иван
// Извлекаем отчество (от второго пробела до конца)
String patronymic = fullName.substring(secondSpace + 1);
System.out.println("Отчество: " + patronymic); // Иванович
// Практический пример: извлекаем домен из email
String email = "user@gmail.com";
int atIndex = email.indexOf('@');
String domain = email.substring(atIndex + 1);
System.out.println("Домен: " + domain); // gmail.com
}
}
Пример 5: Замена и очистка строк
public class StringExample5 {
public static void main(String[] args) {
// Замена символов
String dirty = "Грязь!";
String clean = dirty.replace('!', '.');
System.out.println("После замены: " + clean); // Грязь.
// Замена подстрок
String phrase = "Я люблю Python";
String newPhrase = phrase.replace("Python", "Java");
System.out.println("Новая фраза: " + newPhrase); // Я люблю Java
// Удаление пробелов в начале и конце
String withSpaces = " Привет, мир! ";
String trimmed = withSpaces.trim();
System.out.println("Без пробелов: '" + trimmed + "'"); // 'Привет, мир!'
// Проверка на пустоту
String empty = "";
String blank = " ";
System.out.println("empty.isEmpty(): " + empty.isEmpty()); // true
System.out.println("blank.isEmpty(): " + blank.isEmpty()); // false (есть пробелы)
System.out.println("blank.isBlank(): " + blank.isBlank()); // true (только пробелы)
// Повторение строки
String laugh = "Ха".repeat(3);
System.out.println("Смех: " + laugh); // ХаХаХа
}
}
Пример 6: Разбиение строк и работа с массивами
public class StringExample6 {
public static void main(String[] args) {
// Разбиваем строку по запятой
String csv = "яблоко,груша,банан,апельсин";
String[] fruits = csv.split(",");
System.out.println("Список фруктов:");
for (int i = 0; i < fruits.length; i++) {
System.out.println((i + 1) + ". " + fruits[i]);
}
// Выведет:
// 1. яблоко
// 2. груша
// 3. банан
// 4. апельсин
// Превращаем строку в массив символов
String word = "Java";
char[] letters = word.toCharArray();
System.out.print("Буквы слова Java: ");
for (char letter : letters) {
System.out.print(letter + " "); // J a v a
}
System.out.println();
// Соединяем строки (конкатенация)
String part1 = "Hello";
String part2 = "World";
String result = part1.concat(", ").concat(part2).concat("!");
System.out.println(result); // Hello, World!
// То же самое через +
String result2 = part1 + ", " + part2 + "!";
System.out.println(result2); // Hello, World!
}
}
Пример 7: Сложный пример — валидация пароля
public class StringExample7 {
public static void main(String[] args) {
// Проверяем, соответствует ли пароль требованиям безопасности
String password = "MyP@ssw0rd";
// 1. Длина пароля должна быть не менее 8 символов
boolean isLongEnough = password.length() >= 8;
System.out.println("Длина >= 8: " + isLongEnough); // true
// 2. Пароль должен содержать хотя бы одну цифру
boolean hasDigit = false;
for (int i = 0; i < password.length(); i++) {
if (Character.isDigit(password.charAt(i))) {
hasDigit = true;
break;
}
}
System.out.println("Есть цифра: " + hasDigit); // true
// 3. Пароль должен содержать хотя бы одну заглавную букву
boolean hasUpperCase = false;
for (int i = 0; i < password.length(); i++) {
if (Character.isUpperCase(password.charAt(i))) {
hasUpperCase = true;
break;
}
}
System.out.println("Есть заглавная: " + hasUpperCase); // true
// 4. Пароль не должен содержать пробелов
boolean noSpaces = !password.contains(" ");
System.out.println("Нет пробелов: " + noSpaces); // true
// 5. Проверяем, не совпадает ли пароль с именем пользователя
String username = "user123";
boolean notSameAsUsername = !password.equalsIgnoreCase(username);
System.out.println("Не совпадает с именем: " + notSameAsUsername); // true
// Итоговая проверка
if (isLongEnough && hasDigit && hasUpperCase && noSpaces && notSameAsUsername) {
System.out.println("✅ Пароль надёжный!");
} else {
System.out.println("❌ Пароль не соответствует требованиям");
}
}
}
Пример 8: Работа с форматированием (продвинутый уровень)
public class StringExample8 {
public static void main(String[] args) {
// Форматирование строк (как в Python format)
String name = "Анна";
int age = 25;
double salary = 75000.50;
// Используем String.format()
String formatted = String.format("Имя: %s, Возраст: %d, Зарплата: %.2f", name, age, salary);
System.out.println(formatted); // Имя: Анна, Возраст: 25, Зарплата: 75000.50
// Спецификаторы формата:
// %s — строка
// %d — целое число
// %f — число с плавающей точкой
// %.2f — число с двумя знаками после запятой
// %n — перевод строки
// Сравнение строк с игнорированием пробелов
String str1 = " Java ";
String str2 = "java";
// Сначала trim(), потом equalsIgnoreCase()
boolean areEqual = str1.trim().equalsIgnoreCase(str2);
System.out.println("Строки равны (без учёта пробелов и регистра): " + areEqual); // true
// Проверка, состоит ли строка только из букв
String onlyLetters = "Привет";
String withNumbers = "Привет123";
boolean isOnlyLetters1 = onlyLetters.chars().allMatch(Character::isLetter);
boolean isOnlyLetters2 = withNumbers.chars().allMatch(Character::isLetter);
System.out.println("Только буквы: " + isOnlyLetters1); // true
System.out.println("Только буквы: " + isOnlyLetters2); // false
}
}
Сравнение с Python: чем похоже и чем отличается
Если ты уже знаком с Python, тебе будет проще. Но есть важные различия, которые нужно запомнить:
| Операция | Java | Python | Примечание |
|---|---|---|---|
| Длина строки | str.length() |
len(str) |
В Java это метод, в Python — функция |
| Срез строки | str.substring(1, 4) |
str[1:4] |
В Java — метод, в Python — оператор среза |
| Поиск подстроки | str.indexOf("abc") |
str.find("abc") |
Оба возвращают -1, если не найдено |
| Проверка вхождения | str.contains("abc") |
"abc" in str |
Python использует оператор in |
| Разделение строки | str.split(",") |
str.split(",") |
Очень похоже, но в Java split принимает регулярное выражение |
| Соединение строк | String.join(", ", array) |
", ".join(list) |
Синтаксис почти зеркальный |
| Замена | str.replace("a", "b") |
str.replace("a", "b") |
Почти идентично |
| Регистр | str.toUpperCase() |
str.upper() |
Разные названия, но смысл тот же |
| Удаление пробелов | str.trim() |
str.strip() |
Разные названия |
| Повторение строки | str.repeat(3) |
str * 3 |
В Python — оператор, в Java — метод |
| Форматирование | String.format("%s %d", s, i) |
f"{s} {i}" или "{} {}".format(s, i) |
В Python более гибкое и современное |
| Неизменяемость | Да, строки immutable | Да, строки immutable | В обоих языках строки нельзя изменить |
💡 Совет: Если ты переходишь с Python на Java, запомни главное: в Java почти всё — методы. Вместоlen(str)пишиstr.length(), вместо"abc" in str—str.contains("abc"). Привыкнешь за пару дней.
Типичные ошибки и подводные камни
Ошибка 1: Сравнение строк через ==
String a = "Привет";
String b = new String("Привет");
System.out.println(a == b); // false — разные объекты!
System.out.println(a.equals(b)); // true — правильное сравнение
Почему так происходит? == сравнивает ссылки на объекты, а не их содержимое. equals() сравнивает содержимое. Всегда используй equals().
Ошибка 2: Выход за границы строки
String text = "Кот";
char c = text.charAt(3); // ❌ Ошибка! Индекс 3, а длина 3 (индексы 0, 1, 2)
// Правильно: text.charAt(2) — последний символ 'т'
Запомни: Индексы от 0 до length() - 1. Последний символ всегда charAt(length() - 1).
Ошибка 3: Забыл, что строки неизменяемые
String text = "Привет";
text.toUpperCase(); // ❌ Строка не изменилась!
System.out.println(text); // "Привет"
// Правильно:
text = text.toUpperCase(); // ✅ Присваиваем результат обратно
System.out.println(text); // "ПРИВЕТ"
Ошибка 4: Путаница между isEmpty() и isBlank()
String spaces = " ";
System.out.println(spaces.isEmpty()); // false — есть пробелы
System.out.println(spaces.isBlank()); // true — только пробелы
// Если тебе нужно проверить, есть ли хоть какой-то текст:
if (!spaces.isBlank()) {
System.out.println("Есть текст");
}
Ошибка 5: Неправильное использование split() с точкой
String ip = "192.168.1.1";
String[] parts = ip.split("."); // ❌ Неправильно! Точка — спецсимвол в regex
// Правильно:
String[] parts = ip.split("\."); // ✅ Экранируем точку
Ошибка 6: Забыл про null
String name = null;
int length = name.length(); // ❌ NullPointerException!
// Всегда проверяй на null:
if (name != null) {
System.out.println(name.length());
}
Лучшие практики и советы профессионалов
- Используй StringBuilder для частых изменений. Если ты много раз меняешь строку (например, в цикле), используй
StringBuilder— это в разы быстрее. - Сравнивай строк
// ПЛОХО (создаётся много объектов):
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // Каждая итерация создаёт новую строку!
}
// ХОРОШО (один объект):
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();