/
Программирование
/
Курс Java
/

Неизменяемость строк

Java: Неизменяемость строк

Подумаем, что выведет на экран следующий код:

var company = "hexlet";
company.toUpperCase(); // в верхний регистр
System.out.println(company); // => ?

Кажется, что ответом будет "HEXLET", но это не так. Эта программа выведет "hexlet". Почему?

Дело в том, что строки в Java неизменяемы (или иммутабельны). После создания их содержимое нельзя изменить. Не существует методов, способных поменять саму строку. Любой метод строки только возвращает новую строку, а оригинал остается прежним.

Методы строк не меняют оригинал

Когда мы вызываем метод у строки, кажется, что мы меняем ее. Например, переводим в верхний регистр. На самом деле метод toUpperCase() возвращает новую строку в верхнем регистре, а исходная строка не меняется.

company = "hexlet"

company.toUpperCase()  →  "HEXLET"  (новая строка)
company                →  "hexlet"  (не изменилась)

Чтобы не потерять результат, сохраним его в переменную:

var company = "hexlet";
var upper = company.toUpperCase();
System.out.println(upper); // => HEXLET

Если не сохранить результат метода, он просто потеряется. Другие методы работают так же:

var text = "   hi   ";
var cleaned = text.trim();
System.out.println(cleaned); // => "hi", результат без пробелов
System.out.println(text);    // => "   hi   ", строка не изменилась

Метод trim() вернул новую строку без пробелов по краям, но сам text остался прежним.

Основная причина такого поведения — производительность. Строки и другие примитивные типы данных нельзя менять почти ни в одном современном языке. Неизменяемость позволяет Java переиспользовать одинаковые строки в памяти и экономить ресурсы. Она же упрощает многопоточный код, где одни и те же данные читают сразу несколько потоков.

Вторая причина связана с понятностью кода. Когда мы не изменяем данные, а создаем новые на основе старых, код проще анализировать и модифицировать. Особенно если с данными происходит много преобразований, с этим вам еще предстоит столкнуться. Случайно изменить значение строки невозможно, и это снимает целый класс ошибок.

Как менять данные

Но как же поступать, если данные нужно поменять? Для этого достаточно записать результат метода обратно в ту же переменную:

var language = "JAVA";
language = language.toLowerCase();
System.out.println(language); // => java

Это уместно, когда суть данных не меняется. После toLowerCase() это тот же язык, просто в нижнем регистре.

С другой стороны, в такой ситуации можно создать новую переменную с другим именем:

var language = "JAVA";
var processedLanguage = language.toLowerCase();
System.out.println(processedLanguage); // => java

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

Задание

Данные, вводимые пользователями в формах, часто содержат лишние пробельные символы в конце или начале строки. Кроме того, пользователи могут вводить одно и то же в разном регистре, что потом мешает работе с данными. Поэтому перед тем как добавлять их, данные обрабатывают (говорят нормализуют). В базовую обработку входят два действия:

  • Удаление концевых пробельных символов с помощью метода .trim(), например, было: " hexlet\n ", стало: "hexlet"
  • Приведение к нижнему регистру с помощью метода toLowerCase(). Было: "SUPPORT@hexlet.io", стало: "support@hexlet.io".

Обновите переменную email записав в неё то же самое значение, но обработанное по схеме указанной выше. Распечатайте то, что получилось, на экран.

Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются