String.concat: примеры (JAVA)
String.concat(String str): StringОбзор метода String.concat
В Java метод String.concat служит для объединения двух строк. Официальная сигнатура:
public String concat(String str)
Поведение и назначение:
- Если аргумент
strравенnull, генерируетсяNullPointerException. - Если
str.length() == 0, метод возвращает исходную строку (это тот же объект). - Если текущая строка пуста (длина 0), возвращается сама
str(то есть ссылка на переданный объект). - В остальных случаях возвращается новая строка, содержащая последовательность символов исходной строки, за которой следует последовательность символов аргумента.
Возвращаемое значение: новая строка или одна из исходных ссылок в случаях с пустой строкой. Метод не изменяет исходные объекты, так как String в Java неизменяемый тип.
Сложность по времени пропорциональна сумме длин объединяемых строк. Для многократного конкатенирования рекомендуется рассмотреть альтернативы (см. разделы ниже).
Замечания о реализации: внутреннее представление строк изменилось в Java 9 (компактные строки), но семантика concat осталась прежней. В разных версиях возможны оптимизации при возвращении ссылок при пустых аргументах.
Короткие примеры использования
Несколько простых сценариев с кодом и результатом.
Обычное объединение:
String a = "Hello";
String b = " World";
String c = a.concat(b);
System.out.println(c);
Hello World
Пустая вторая строка возвращает исходную ссылку:
String a = "Hi";
String b = "";
String c = a.concat(b);
System.out.println(c == a); // сравнение ссылок
true
Пустая первая строка возвращает ссылку на аргумент:
String a = "";
String b = "nonempty";
String c = a.concat(b);
System.out.println(c == b);
true
Передача null вызывает исключение:
String a = "x";
String b = null;
String c = a.concat(b);
// бросит NullPointerException
Exception in thread "main" java.lang.NullPointerException at java.lang.String.concat(String.java:...) ...
Альтернативы в Java и их отличия
- Оператор + - синтаксический сахар, который при компиляции ряда литералов может быть оптимизирован; при динамическом объединении в цикле ведет к созданию временных объектов.
- StringBuilder.append - предпочтителен при множественных операциях конкатенации в циклах, потому что минимизирует выделения памяти и копирования.
- StringBuffer.append - похож на StringBuilder, но синхронизирован; уместен в многопоточных сценариях, где требуется потокобезопасность.
- String.join - удобен для объединения коллекций/массива с разделителем; эффективен и читабелен для множественных элементов.
- Collectors.joining (Streams) - применяется при работе со стримами, более выразителен и избегает явных циклов.
- String.format - для форматированного объединения с шаблоном; удобен при необходимости вставки форматов и локализации.
Вариант использования выбирается в зависимости от частоты операций и требований к производительности и потокобезопасности.
Сравнение с похожими функциями в других языках
Краткие отличия и примеры для распространённых языков.
- JavaScript: метод
concatи оператор+. Конкатенация сnullдаёт строку "null" при использовании +.
let a = "Hi";
let b = null;
console.log(a + b);
console.log(a.concat(" ", "JS"));
Hinull Hi JS
- Python: оператор
+для строк; конкатенация сNoneвызовет TypeError. Более эффективно использоватьstr.joinдля списка.
a = "Hi"
b = None
# a + b # TypeError
print(" ".join(["a","b"]))
a b
- PHP: оператор
.. При конкатенации сnullобычно получается пустая строка для null-переменной.
$a = "Hi";
$b = null;
echo $a . $b;
Hi
- C#:
String.Concatи оператор+. В C#nullтрактуется как пустая строка при использовании String.Concat, то есть не бросает исключение.
string a = "Hi";
string b = null;
Console.WriteLine(string.Concat(a, b));
Hi
- Go: оператор
+для строк. Значениеnilдля строк в Go не существует, нулевого указателя для string нет; пустая строка используется по умолчанию.
a := "Hi"
b := ""
fmt.Println(a + b)
Hi
- Kotlin: оператор
+и функцияplus. Приnullтребуется безопасный вызов или явная проверка.
val a: String = "Hi"
val b: String? = null
println(a + b) // "Hinull" если b неявно приведен
println(a.plus(b ?: ""))
Hinull Hi
- Lua: оператор
..для конкатенации; конкатенация с nil вызывает ошибку.
a = "Hi"
b = nil
-- print(a .. b) -- error
print(a .. " Lua")
Hi Lua
- SQL: в большинстве диалектов используется оператор
||или функцияCONCAT. Обработка NULL зависит от СУБД (часто NULL в результате делает весь результат NULL, но есть функции COALESCE/IFNULL для обхода).
-- в PostgreSQL
SELECT 'a' || NULL || 'b';
-- в MySQL
SELECT CONCAT('a', NULL, 'b');
-- PostgreSQL: NULL -- MySQL: NULL (CONCAT возвращает NULL при любом NULL аргументе)
Ключевое отличие Java: String.concat бросает NullPointerException при null-аргументе, тогда как в других языках поведение варьируется от преобразования в "null" до игнорирования или генерации ошибки.
Типичные ошибки и их проявления
Несколько распространённых проблем при использовании String.concat.
1) NullPointerException при передаче null:
String s = "a";
s.concat(null);
Exception in thread "main" java.lang.NullPointerException at java.lang.String.concat(String.java:...) ...
2) Ожидание изменения исходной строки (ошибочное предположение о мутабельности):
String s = "a";
s.concat("b");
System.out.println(s);
a
Пояснение: метод возвращает новую строку, исходный объект остаётся прежним.
3) Низкая производительность при конкатенировании в цикле:
String res = "";
for (String part : parts) {
res = res.concat(part);
}
Для большого числа элементов приводит к множественным аллокациям и копированию; рекомендуется StringBuilder.
4) Неправильные ожидания при работе с кодировками и многобайтовыми символами: метод оперирует символами (UTF-16 code units), поэтому при работе с суррогатными парами и индексами нужно учитывать специфику.
Изменения в реализации в последних версиях
Семантика метода String.concat в Java не претерпела изменений: сигнатура и поведение остались совместимыми. Основные изменения касаются внутренней реализации строк:
- В Java 9 введено компактное представление строк (byte[] + coder), что повлияло на внутреннюю реализацию операций с символами и памятью, но не изменило внешнее поведение
concat. - В последующих релизах могли появиться оптимизации аллокаций и копирования, однако API и исключения остались прежними.
Расширенные и редкие сценарии применения
Несколько продвинутых примеров с объяснениями.
1) Безопасная конкатенация, допускающая null, с использованием Objects.toString:
String a = "start";
String b = null;
String result = a.concat(Objects.toString(b, ""));
System.out.println(result);
start
Пояснение: Objects.toString(b, "") превращает null в пустую строку и предотвращает NullPointerException.
2) Использование concat при обработке substrings и сохранении ссылок (проверка оптимизаций):
String a = "";
String b = "payload";
String c = a.concat(b);
System.out.println(c == b);
true
Пояснение: при пустой левой строке возвращается ссылка на правую. Это может использоваться для экономии памяти при комбинации с пустыми фрагментами.
3) Неподходящий вариант при сборке больших строк: сравнение с StringBuilder:
// Плохо: много аллокаций
String s = "";
for (int i = 0; i < 10000; i++) s = s.concat("x");
// Лучше
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) sb.append('x');
String good = sb.toString();
Первый вариант медленный и потребляет больше памяти; второй вариант предпочтительнее.
4) Использование в Stream.reduce: неэффективность и альтернатива:
List parts = Arrays.asList("a","b","c");
String reduced = parts.stream().reduce("", String::concat);
System.out.println(reduced);
// Лучше
String joined = parts.stream().collect(Collectors.joining());
System.out.println(joined);
abc abc
Пояснение: reduce с конкатенацией создаёт множество временных строк; Collectors.joining использует оптимизации.
5) Конкатенация больших массивов строк с предварительным вычислением итоговой длины (редко используемый ручной оптимизируемый вариант):
String[] arr = {"one","two","three"};
int total = 0;
for (String s : arr) total += s.length();
StringBuilder sb = new StringBuilder(total);
for (String s : arr) sb.append(s);
String result = sb.toString();
System.out.println(result);
onetwothree
Пояснение: предварительное выделение места в StringBuilder минимизирует дополнительные аллокации.
6) Комбинация с интернированием и экономией памяти (редкий кейс):
String a = "Hello";
String b = " World";
String c = a.concat(b).intern();
System.out.println(c == ("Hello World"));
true
Пояснение: intern() может быть использован для хранения единственного экземпляра строки в пуле, но использование intern имеет побочные эффекты на работу GC и память и требует осторожности.