W3docs

Конкатенация строк в Java

Объединяйте строки в Java с помощью оператора +, concat() и StringBuilder, и сравнивайте их производительность.

«Конкатенация» означает объединение строк одна за другой. Java предоставляет несколько способов это сделать — +, concat, String.format, текстовые блоки, StringBuilder, String.join. Они различаются по читаемости и, при использовании в циклах, по производительности.

Оператор +

+ — самый распространённый способ:

String first = "Ada";
String last = "Lovelace";
String full = first + " " + last;     // "Ada Lovelace"

Он также преобразует нестроковые типы в строки через их toString():

int age = 36;
String s = "Age: " + age;             // "Age: 36"

За кулисами компилятор превращает a + b + c в единственный вызов StringBuilder.append(...).append(...).toString(). Поэтому одно цепочечное выражение с + работает эффективно.

concat

String.concat(other) возвращает текущую строку, за которой следует other:

"Hello, ".concat("World!");    // "Hello, World!"

Это фактически то же самое, что +, но принимает только String (без автоконвертации). В большинстве кода просто используется +.

String.format и formatted

Для конкатенации нескольких частей с форматированием, специфичным для типов, String.format выглядит чище, чем длинные цепочки +:

String name = "Ada";
int age = 36;
String s = String.format("%s is %d years old", name, age);

Начиная с Java 15, метод экземпляра formatted является эквивалентом и читается слева направо:

"%s is %d years old".formatted(name, age);

Текстовые блоки для многострочных строк

Для многострочных строк синтаксис текстовых блоков (Java 15+) позволяет избежать длинных цепочек с \n:

String json = """
        {
          "name": "%s",
          "age": %d
        }
        """.formatted(name, age);

StringBuilder — для циклов

Строки Java неизменяемы — после создания String никогда не меняется. Поэтому каждое использование + со String создаёт совершенно новый объект. В цикле с тысячами итераций это означает большое количество короткоживущих объектов и копирований. Вместо этого используйте StringBuilder — у него есть единственный изменяемый внутренний буфер, который растёт на месте:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("line ").append(i).append("\n");
}
String result = sb.toString();

Методы StringBuilder, которые вам понадобятся:

  • append(any) — добавить в конец (возвращает строитель, чтобы можно было выстраивать цепочки).
  • insert(index, any) — вставить на определённую позицию.
  • delete(start, end) — удалить диапазон.
  • reverse() — перевернуть содержимое строителя.
  • length() и setLength(n) — прочитать / усечь.
  • toString() — получить итоговую String.

Существует также StringBuffer, который идентичен, но потокобезопасен (каждый метод является synchronized). Он почти никогда не нужен — используйте StringBuilder, если только вы не разделяете строитель между потоками намеренно.

String.join — для коллекций

Когда у вас есть коллекция строк и разделитель, String.join — самый чистый вариант:

String csv = String.join(",", "a", "b", "c");        // "a,b,c"
String csv2 = String.join(", ", List.of("a", "b", "c"));   // "a, b, c"

Для более сложного объединения (коллекторы, условное включение) смотрите Collectors.joining из потоков далее в книге.

Когда что использовать

Примерное дерево решений:

  • Одна или две части, читаются слева направо+.
  • Несколько частей с форматированием типовString.format или formatted.
  • Многострочный литерал → текстовый блок, опционально с .formatted.
  • Построение по частям в циклеStringBuilder.
  • Объединение коллекции с разделителемString.join.

Для небольших конкатенаций современные компиляторы и JVM (с конкатенацией строк на основе invokedynamic, введённой в Java 9) делают + очень быстрым — производительность не является причиной избегать его в простых случаях.

Демонстрация случая с циклом

java— editable, runs on the server

Что дальше

Специальные символы и управляющие последовательности Java — что делают \n, \t, \" и юникодные управляющие последовательности.

Практика

Практика
Какой подход лучше всего подходит для построения длинной строки внутри цикла с 10 000 итерациями?
Какой подход лучше всего подходит для построения длинной строки внутри цикла с 10 000 итерациями?
Was this page helpful?