← Назад к вопросам

Что такое конкатенация строк?

1.0 Junior🔥 131 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Конкатенация - это операция объединения нескольких строк в одну. В Java это можно делать несколькими способами, каждый из которых имеет разные характеристики производительности.

Что такое конкатенация

Букваль это просто объединение содержимого строк в новую строку:

// Простой пример конкатенации
String firstName = "John";
String lastName = "Doe";
String fullName = firstName + " " + lastName; // "John Doe"

Это выглядит просто, но под капотом происходит много действий.

Способ 1: Оператор + (плюс)

// Самый простой и читаемый способ
String result = "Hello" + " " + "World";
System.out.println(result); // "Hello World"

// Компилятор преобразует это в StringBuilder операции
// Эквивалент:
String result = new StringBuilder()
    .append("Hello")
    .append(" ")
    .append("World")
    .toString();

Способ 2: StringBuilder (РЕКОМЕНДУЕТСЯ для циклов)

// Когда нужно объединить много строк
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("Item ");
    sb.append(i);
    sb.append("\n");
}
String result = sb.toString();

Способ 3: String.concat()

// Метод объединения для одной операции
String result = "Hello".concat(" ").concat("World");
// Но это создает промежуточные String объекты

Способ 4: String.join()

// Хорош когда есть коллекция элементов
List<String> words = Arrays.asList("Hello", "World", "Java");
String result = String.join(" ", words); // "Hello World Java"

// Тоже работает с массивом
String result = String.join("-", "2024", "03", "22"); // "2024-03-22"

Способ 5: String.format() или printf

// Для форматированного вывода
String name = "Alice";
int age = 30;
String result = String.format("Name: %s, Age: %d", name, age);
// "Name: Alice, Age: 30"

// Или с printf
System.out.printf("Name: %s, Age: %d%n", name, age);

Способ 6: StringJoiner

// Для конкатенации с разделителем и префиксом/суффиксом
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("Apple");
joiner.add("Banana");
joiner.add("Cherry");
String result = joiner.toString(); // "[Apple, Banana, Cherry]"

Проблема производительности

// ❌ ПЛОХО - очень неэффективно
String result = "";
for (int i = 0; i < 10000; i++) {
    result = result + "Item " + i; // Создает 10000 новых String объектов!
    // Это O(n^2) сложность!
}

// Почему плохо:
// Итерация 1: result = "" + "Item 0" = "Item 0" (создано 1 String)
// Итерация 2: result = "Item 0" + "Item 1" = "Item 0Item 1" (создано 2 String)
// Итерация 3: результат уже занимает 20 байт, копируется в новый String
// ...
// Итерация 10000: копируется вся строка + новый элемент
// ✅ ХОРОШО - эффективно
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append("Item ").append(i);
    // O(n) сложность - каждое добавление быстрое
}
String result = sb.toString();

Разница в производительности

public class StringConcatenationBenchmark {
    public static void main(String[] args) {
        // Тест 1: Оператор + в цикле
        long start = System.currentTimeMillis();
        String result = "";
        for (int i = 0; i < 10000; i++) {
            result = result + i;
        }
        long time1 = System.currentTimeMillis() - start;
        System.out.println("+ оператор: " + time1 + "ms"); // ~1000ms
        
        // Тест 2: StringBuilder
        start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append(i);
        }
        result = sb.toString();
        long time2 = System.currentTimeMillis() - start;
        System.out.println("StringBuilder: " + time2 + "ms"); // ~1ms
        
        // Разница: 1000x медленнее!
        System.out.println("Разница: " + (time1 / time2) + "x");
    }
}

Внутреннее устройство StringBuilder

// StringBuilder хранит char[] буфер, который растет при необходимости
public final class StringBuilder extends AbstractStringBuilder {
    private char[] value; // Буфер
    private int count;    // Текущая длина
    
    // Когда буфер полный, он увеличивается на 50% + 2
    private void ensureCapacityInternal(int minimumCapacity) {
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value, 
                value.length * 2 + 2);
        }
    }
    
    public StringBuilder append(String str) {
        if (str == null) {
            return appendNull();
        }
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
}

String конкатенация компилятором

// Компилятор оптимизирует простую конкатенацию
String result = "Hello" + " " + "World";

// Компилятор видит, что это литералы, и объединяет на этапе компиляции
// Становится:
String result = "Hello World";

// Но если есть переменные:
String name = "John";
String result = "Hello " + name + " World";

// Компилятор преобразует в StringBuilder:
String result = new StringBuilder()
    .append("Hello ")
    .append(name)
    .append(" World")
    .toString();

StringBuffer vs StringBuilder

// StringBuffer - синхронизированный (старый, медленный)
StringBuffer buffer = new StringBuffer();
buffer.append("text"); // synchronized

// StringBuilder - несинхронизированный (новый, быстрый)
StringBuilder builder = new StringBuilder();
builder.append("text"); // не synchronized

// StringBuilder ~2x быстрее, используй его в однопоточном коде

Best Practices

// 1. Для простой конкатенации - используй +
String greeting = "Hello, " + name;

// 2. В цикле - используй StringBuilder
StringBuilder sb = new StringBuilder();
for (String item : items) {
    sb.append(item);
}

// 3. Для коллекций - используй String.join()
String csv = String.join(",", values);

// 4. Для форматирования - используй String.format()
String formatted = String.format("%.2f", price);

// 5. Предварительно выделяй емкость если знаешь размер
StringBuilder sb = new StringBuilder(1000); // Вместо 16 по умолчанию

// 6. Не используй StringBuffer в новом коде
// StringBuffer уже устарел

Примеры из реальной работы

// Построение SQL запроса
StringBuilder query = new StringBuilder();
query.append("SELECT * FROM users WHERE ");
for (int i = 0; i < conditions.size(); i++) {
    if (i > 0) query.append(" AND ");
    query.append(conditions.get(i));
}

// Построение JSON
StringBuilder json = new StringBuilder("{");
json.append("\"name\":\"").append(name).append("\",");
json.append("\"age\":").append(age);
json.append("}");

// Построение CSV файла
StringBuilder csv = new StringBuilder();
for (Record record : records) {
    csv.append(record.getId()).append(",")
       .append(record.getName()).append(",")
       .append(record.getEmail()).append("\n");
}

Вывод

Конкатенация - это объединение строк в одну. В Java есть несколько способов:

  1. Оператор + - хорошо для простых случаев, компилятор оптимизирует
  2. StringBuilder - обязателен для циклов и многократных объединений
  3. String.join() - удобен для коллекций
  4. String.format() - для форматирования
  5. StringJoiner - для разделителей и префиксов

Критическое правило: НИКОГДА не конкатенируй в цикле с +, используй StringBuilder!