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

Что знаешь о String

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

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

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

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

String в Java — полный гайд

String — один из самых часто используемых классов в Java. Понимание его особенностей, иммутабельности и оптимизаций критично для написания эффективного кода.

Иммутабельность (Immutability)

String объекты в Java **неизменяемы**. После создания строку нельзя изменить:

String str = "Hello";
str.concat(" World"); // Это не изменит str!
System.out.println(str); // "Hello"

// concat() возвращает новую строку
String newStr = str.concat(" World");
System.out.println(newStr); // "Hello World"

Почему это важно:

  • Потокобезопасность: одну строку могут читать многие потоки одновременно
  • Безопасность: строки хранят пароли, токены и не могут быть изменены
  • Оптимизация: JVM может кэшировать и переиспользовать строки
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true! Одна и та же строка в памяти

String s3 = new String("Hello");
System.out.println(s1 == s3); // false! Разные объекты
System.out.println(s1.equals(s3)); // true! Одинаковое содержимое

String Pool (Пул строк)

JVM поддерживает специальную область памяти — String Pool, где хранятся уникальные строковые литералы:

// В String Pool
String literal1 = "Java"; // Добавляется в pool
String literal2 = "Java"; // Берется из pool
System.out.println(literal1 == literal2); // true

// Не в String Pool
String obj1 = new String("Java");
String obj2 = new String("Java");
System.out.println(obj1 == obj2); // false (разные объекты в heap)

// intern() добавляет строку в pool
String obj3 = new String("Java").intern();
System.out.println(literal1 == obj3); // true!

Операции со String

String str = "Hello World";

// Получение длины
int length = str.length(); // 11

// Получение символа по индексу
char ch = str.charAt(0); // H

// Поиск подстроки
int index = str.indexOf("World"); // 6
boolean contains = str.contains("World"); // true

// Подстрока
String sub = str.substring(0, 5); // "Hello"

// Замена
String replaced = str.replace("World", "Java"); // "Hello Java"

// Преобразование регистра
String upper = str.toUpperCase(); // "HELLO WORLD"
String lower = str.toLowerCase(); // "hello world"

// Удаление пробелов
String trimmed = "  Hello  ".trim(); // "Hello"

// Разделение по разделителю
String[] parts = str.split(" "); // ["Hello", "World"]

// Проверка начала/конца
boolean startsWith = str.startsWith("Hello"); // true
boolean endsWith = str.endsWith("World"); // true

Сравнение строк

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");

// == сравнивает ссылки (адреса в памяти)
System.out.println(s1 == s2); // true (String Pool)
System.out.println(s1 == s3); // false (разные объекты)

// equals() сравнивает содержимое
System.out.println(s1.equals(s3)); // true

// equalsIgnoreCase() игнорирует регистр
System.out.println(s1.equalsIgnoreCase("HELLO")); // true

// compareTo() для лексикографического сравнения
System.out.println("ABC".compareTo("ABC")); // 0 (равны)
System.out.println("ABC".compareTo("DEF")); // -3 (ABC < DEF)

StringBuilder vs StringBuffer vs String

// ❌ Неэффективно — много новых объектов в памяти
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i; // Каждый раз создается новая строка!
}

// ✅ Эффективно — используем StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i); // Добавляем в одну переменную
}
String result = sb.toString();

Сравнение:

КлассИммутабельныйПотокобезопасныйСкорость
StringДаДаМедленно при изменениях
StringBuilderНетНетБыстро, предпочтительно
StringBufferНетДаМедленнее, legacy

String Formatting

// Способ 1: concat и +
String name = "Alice";
String msg = "Hello, " + name + "!";

// Способ 2: format() (как printf в C)
String formatted = String.format("Hello, %s! You are %d years old", "Bob", 25);

// Способ 3: Text Blocks (Java 13+)
String html = """
    <html>
        <body>Hello</body>
    </html>
    """;

// Способ 4: String.join()
String joined = String.join(", ", "A", "B", "C"); // "A, B, C"

// Способ 5: StringBuilder
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(", ").append("World");
String result = sb.toString();

Утечки памяти со String

// ❌ Потенциальная утечка памяти
public static void main(String[] args) {
    String source = new String("Very large string with lots of data...");
    String substring = source.substring(0, 5); // "Very "
    
    // substring удерживает ссылку на весь source в памяти!
    // Даже если source больше не нужен, он не будет удален
}

// ✅ Решение в старых версиях Java
String substring = new String(source.substring(0, 5));

// В Java 11+ это уже оптимизировано — substring создает новый массив символов

Строки и Null

String str = null;

// ❌ NullPointerException
System.out.println(str.length()); // NPE!

// ✅ Проверка перед использованием
if (str != null && str.length() > 0) {
    System.out.println(str);
}

// ✅ Java 8+: Optional
Optional.ofNullable(str).ifPresent(System.out::println);

// ✅ Java 7+: Objects.requireNonNull()
String safeStr = Objects.requireNonNull(str, "String cannot be null");

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

// Плохо: много одинаковых строк в памяти
for (int i = 0; i < 1000000; i++) {
    String key = "constant_key"; // Каждый раз создается новый объект
}

// Хорошо: используем String literal
String key = "constant_key"; // Один раз в pool
for (int i = 0; i < 1000000; i++) {
    // Переиспользуем одну строку
}

// Или явное интернирование
Set<String> uniqueStrings = new HashSet<>();
for (String str : largeList) {
    uniqueStrings.add(str.intern()); // Избегаем дубликатов в памяти
}

Regex с String

String text = "Hello123World456";

// Проверка паттерна
boolean hasNumbers = text.matches(".*\\d+.*"); // true

// Замена по паттерну
String replaced = text.replaceAll("\\d+", "X"); // "HelloXWorldX"

// Разделение по паттерну
String[] parts = text.split("\\d+"); // ["Hello", "World", ""]

// Поиск совпадений
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
    System.out.println(matcher.group()); // 123, 456
}

Лучшие практики

// 1. Используйте equals(), не ==
String a = "test";
String b = new String("test");
if (a.equals(b)) { } // Правильно
if (a == b) { } // Неправильно

// 2. Используйте StringBuilder для множественных конкатенаций
StringBuilder sb = new StringBuilder();
for (...) {
    sb.append(...); // Хорошо
}

// 3. Избегайте substring() на очень больших строках
// в старых Java версиях

// 4. Кэшируйте результаты intern() если часто используется
private static final String COMMON = "very_common_string".intern();

// 5. Используйте String.valueOf() вместо toString()
int num = 42;
String str = String.valueOf(num); // Может вернуть кэшированное значение