Конкатенация строк в Java
Конкатенация строк (сцепление) — это операция объединения строк. В Java для неё используется оператор +, а также его составная форма +=. К строке можно присоединить значение любого типа — число, символ, объект — и оно будет автоматически преобразовано к строке. Один и тот же знак + означает то сложение, то конкатенацию, и различить эти случаи помогает одно простое правило.
Когда + означает конкатенацию, а когда сложение
Важно запомнить всего два правила:
- Если хотя бы один из операндов имеет тип String, оператор
+выполняет конкатенацию строк, а второй операнд автоматически преобразуется к строке. - Если оба операнда — числа (или другие числовые типы, включая
char), оператор+выполняет арифметическое сложение.
| Операнды | Что делает + | Пример | Результат |
|---|---|---|---|
String + String | Конкатенация | "Hello " + "world" | "Hello world" |
String + любой другой тип | Конкатенация (операнд преобразуется к строке) | "x=" + 5 | "x=5" |
| число + число | Сложение | 4 + 5 | 9 |
char + char | Сложение кодов символов | 'X' + 'Y' | 177 |
В простейшем случае объединяются две строки:
public class StringExample1 {
public static void main(String[] args) {
String str1 = "world";
System.out.println("Hello " + str1);
System.out.println("First line\n" + "Second line");
}
} Совет
Для строк работает и составной оператор +=: запись str += " world"; эквивалентна str = str + " world";. Присоединять через += можно значение любого типа — оно, как и при обычной конкатенации, будет преобразовано к строке.
char в конкатенации: почему получается 177
На типе char легко ошибиться. В первом System.out.println следующего примера на консоль выводится строка «X Y»: мы объединяем char со String, и это конкатенация. Во втором же System.out.println выводится не строка, как многие ожидают, а число 177. Тип char — псевдоцелочисленный и может участвовать в арифметических операциях: строки в выражении нет, поэтому складываются коды символов — 88 + 89 = 177:
public class StringExample2 {
public static void main(String[] args) {
char x, y;
x = 88; // Код символа 'X'
y = 'Y';
System.out.println(x + " " + y); // Выведется X Y
System.out.println(x + y); // Выведется 177
}
} Чтобы вывести два символа рядом без пробела, достаточно ввести в выражение пустую строку: System.out.println("" + x + y) напечатает XY.
Порядок вычисления: слева направо
Выражение с несколькими + вычисляется слева направо, но сначала выполняются операции с более высоким приоритетом. В следующем примере на консоль выводится str=48: умножение имеет больший приоритет, чем сложение, поэтому сначала 4 * 2 даёт 8. Дальше слева направо: "str=" + 4 — это уже конкатенация, результат "str=4", а затем "str=4" + 8 даёт "str=48":
public class StringExample3 {
public static void main(String[] args) {
System.out.println("str=" + 4 + 4 * 2);
}
} Если числа нужно именно сложить, порядок меняют скобками: "str=" + (4 + 4 * 2) выведет str=12. Работает и обратное: пока строки слева нет, + остаётся сложением — выражение 1 + 2 + "3" даёт "33", потому что сначала складываются числа 1 + 2, и только потом результат 3 присоединяется к строке.
Важно
Как только при вычислении слева направо в выражении встретилась String, оператор + «переключается» в режим конкатенации и обратно уже не возвращается: всё, что правее, присоединяется как строка. Именно поэтому "str=" + 4 + 8 даёт str=48, а не str=12.
Unicode в строковых литералах
В строковых литералах, как и в переменных типа char, можно использовать Unicode-эскейпы \u с шестнадцатеричным кодом символа:
public class StringExample4 {
public static void main(String[] args) {
// Слово "Украина" в кодировке Unicode
System.out.println("\u0423\u043A\u0440\u0430\u0438\u043D\u0430");
}
} Компилятор декодирует такие последовательности ещё до разбора программы, поэтому на консоль выводится обычное слово «Украина».
Сравнение строк: equals(), а не ==
String — ссылочный тип, поэтому оператор сравнения == сравнивает не содержимое строк, а ссылки — указывают ли обе переменные на один и тот же объект в памяти. Из-за пула строковых литералов == иногда «случайно» возвращает true, но для строк, созданных во время работы программы (в том числе полученных конкатенацией переменных), он ненадёжен. Содержимое строк сравнивают методом equals() или Objects.equals() (начиная с Java 7) — второй вариант дополнительно безопасен при null:
import java.util.Objects;
public class StringExample5 {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hi";
System.out.println(str1.equals(str2));
System.out.println(Objects.equals(str1, str2));
}
} Длина строки: метод length()
Длина строки определяется с помощью метода length() — он возвращает количество символов:
public class StringExample6 {
public static void main(String[] args) {
String str = "Hello";
System.out.println("Длина строки: " + str.length());
}
} Обратите внимание: здесь тоже работает конкатенация — число str.length() автоматически преобразуется к строке и присоединяется к сообщению.
Часто задаваемые вопросы
Что будет при конкатенации строки с null?
Исключения не будет: выражение "значение: " + s при s == null вернёт строку "значение: null" — вместо ссылки подставляется текст «null». NullPointerException возникнет, только если вызвать у такой переменной метод, например s.length() или s.concat("...").
Почему "1" + 2 + 3 даёт "123", а 1 + 2 + "3" даёт "33"?
Выражение вычисляется слева направо. В первом случае строка стоит первой, поэтому оба сложения — конкатенации: "1" + 2 даёт "12", затем "12" + 3 даёт "123". Во втором случае сначала складываются числа 1 + 2 = 3, и лишь потом результат присоединяется к строке: 3 + "3" даёт "33".
Когда вместо конкатенации использовать StringBuilder?
В циклах и при многошаговой сборке длинного текста. Строки в Java неизменяемы, поэтому str += ... в цикле на каждой итерации создаёт новый объект строки. StringBuilder накапливает символы в изменяемом буфере методом append() и в конце отдаёт результат одним вызовом toString(). Для одиночного выражения из нескольких + компилятор оптимизирует конкатенацию сам.
Чем оператор + отличается от метода concat()?
Метод concat() принимает только String и бросает NullPointerException, если вызвать его у null-переменной. Оператор + универсальнее: он принимает операнд любого типа, сам преобразует его к строке и спокойно обрабатывает null. На практике почти всегда используют +; concat() встречается редко.
Презентацию с видео можно скачать на Patreon.
Видео объяснение
Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.
Комментарии