String ·
‹ Previous Next ›
⏱ 5 min read Modified: 2026-10-16

Класс String в Java: что это и основные методы

Типичная первая ошибка со строками: вызвать s.toUpperCase() и ожидать, что строка изменится. После String s = "java"; s.toUpperCase(); System.out.println(s); на экране по-прежнему java — метод вернул новую строку "JAVA", а результат просто потеряли.

String в Java — это класс java.lang.String, объект которого хранит неизменяемую (immutable) последовательность символов. Любой строковый литерал в кавычках, например "Hello", — объект String. Методы класса (equals(), substring(), replace(), toUpperCase() и др.) никогда не меняют исходную строку, а возвращают новую.

Для работы со строками в пакете java.lang, который подключается автоматически, есть три класса: String, StringBuilder и StringBuffer. Все они объявлены как final, поэтому унаследоваться от них нельзя. В этом уроке разбираем класс String; изменяемым строкам посвящён урок StringBuilder и StringBuffer.

Неизменяемость String

Строка в Java неизменяема: после создания объекта String его символы поменять нельзя. Методы, которые «изменяют» строку, создают и возвращают новый объект, поэтому их результат нужно присвоить переменной: s = s.toUpperCase();.

public class ImmutableExample {
    public static void main(String[] args) {
        String s = "java";
        s.toUpperCase();          // результат потерян
        System.out.println(s);    // Вывод: java

        s = s.toUpperCase();      // переменная теперь ссылается на новую строку
        System.out.println(s);    // Вывод: JAVA
    }
}

Именно поэтому у String нет методов вроде setCharAt(), append() или reverse(): они есть у изменяемых классов StringBuilder и StringBuffer — подробнее в уроке StringBuilder и StringBuffer.

Запомните

Неизменяем объект, а не переменная. Строку "java" поменять нельзя, но переменную s можно перенаправить на другой объект. Если строку нужно много раз менять в цикле, используйте StringBuilder: каждое s = s + x создаёт новый объект String.

Основные методы класса String

Чаще всего в Java используют методы String для сравнения (equals(), compareTo()), поиска (indexOf(), contains()), извлечения частей (charAt(), substring()) и преобразования (replace(), toUpperCase(), trim()). Сводка с примерами и граничными случаями:

Метод Что делает Пример → результат Граничный случай
length() Длина строки (число char) "abc".length() → 3 "".length() → 0
charAt(i) Символ по индексу (с 0) "abc".charAt(1) → 'b' Индекс вне диапазона → StringIndexOutOfBoundsException
equals(s) Сравнивает содержимое "Hi".equals("Hi") → true Вызов на null → NullPointerException
equalsIgnoreCase(s) Сравнение без учёта регистра "Hi".equalsIgnoreCase("HI") → true Аргумент null → false
compareTo(s) Лексикографическое сравнение "a".compareTo("b") → -1 Заглавные буквы «меньше» строчных
indexOf(x) Индекс первого вхождения "hello".indexOf('l') → 2 Не найдено → -1
lastIndexOf(x) Индекс последнего вхождения "hello".lastIndexOf('l') → 3 Не найдено → -1
contains(s) Есть ли подстрока "Foobar".contains("oo") → true contains("") → true
startsWith(s) / endsWith(s) Проверка начала / конца "Foobar".endsWith("bar") → true Регистр учитывается
substring(b, e) Подстрока с b по e-1 "Hello".substring(1, 3) → "el" b > e → StringIndexOutOfBoundsException
replace(a, b) Заменяет все вхождения символа или подстроки "Hello".replace('l', 'w') → "Hewwo" Не регулярное выражение (для regex — replaceAll())
toLowerCase() / toUpperCase() Смена регистра "Hello".toUpperCase() → "HELLO" Зависит от локали по умолчанию
trim() / strip() Удаляет пробелы по краям " Hi ".trim() → "Hi" strip() (Java 11) понимает Unicode-пробелы
isEmpty() / isBlank() Пустая / пустая или из пробелов " ".isBlank() → true " ".isEmpty() → false
concat(s) Присоединяет строку "Hello".concat("!") → "Hello!" Аргумент null → NullPointerException
String.join(d, ...) Склеивает через разделитель (Java 8) String.join("-", "a", "b") → "a-b" Элемент null превращается в "null"
String.valueOf(x) Любое значение → строка String.valueOf(42) → "42" (Object) null → "null"
repeat(n) Повторяет строку n раз (Java 11) "ab".repeat(3) → "ababab" n < 0 → IllegalArgumentException
toCharArray() Копия символов в массив char[] "abc".toCharArray() → [a, b, c] Изменение массива не меняет строку
split(regex) Разбивает строку по шаблону "a,b".split(",") → [a, b] Аргумент — регулярное выражение: split(".") вернёт пустой массив

Метод split() принимает регулярное выражение — он подробно разобран в уроке Регулярные выражения, а форматирование через String.format() — в уроке Форматирование строк.

Создание строк и длина строки

Строку в Java создают литералом (String s = "abc";) или конструктором (new String(...)) из массива символов, массива байтов или другой строки. Длину строки возвращает метод length() — это метод, а не поле, как у массива.

Класс String поддерживает несколько конструкторов, например:

  • String() — пустая строка;
  • String(String original) — копия другой строки;
  • String(char[] value) и String(char[] value, int offset, int count) — из массива символов;
  • String(byte[] bytes) и String(byte[] bytes, Charset charset) — из массива байтов;
  • String(StringBuffer buffer), String(StringBuilder builder) и др.

Рассмотрим разные варианты создания строк:

public class StringExample1 {
    public static void main(String[] args) {
        String str1 = new String();
        System.out.println("str1:[" + str1 + "]");

        char[] chars1 = {'a', 'b', 'c'};
        String str2 = new String(chars1);
        System.out.println("str2:" + str2);

        char[] chars2 = {'a', 'b', 'c', 'd', 'e', 'f'};
        String str3 = new String(chars2, 2, 3);
        System.out.println("str3:" + str3);

        String str4 = "abc";
        System.out.println("str4:" + str4);
        System.out.println("str4.length:" + str4.length());
        System.out.println("abc.length:" + "abc".length());

        String str5 = new String(str4);
        System.out.println("str5:" + str5);
    }
}
str1:[]
str2:abc
str3:cde
str4:abc
str4.length:3
abc.length:3
str5:abc

В следующем примере строки создаются из массива типа byte. Конструктор String(byte[]) декодирует байты кодировкой по умолчанию (начиная с Java 18 это UTF-8); если кодировка известна, лучше передать её явно: new String(bytes, StandardCharsets.UTF_8).

public class StringExample2 {
    public static void main(String[] args) {
        byte[] bytes = {65, 66, 67, 68, 69, 70};

        String s1 = new String(bytes);
        System.out.println(s1);       // Вывод: ABCDEF

        String s2 = new String(bytes, 2, 3);
        System.out.println(s2);       // Вывод: CDE
    }
}

Сравнение строк: equals(), equalsIgnoreCase() и ==

Содержимое строк в Java сравнивают методом equals(), а без учёта регистра — методом equalsIgnoreCase(). Оператор == сравнивает не текст, а ссылки: он показывает, указывают ли две переменные на один и тот же объект.

public class EqualsExample {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = "Good-bye";
        String s4 = "HELLO";
        System.out.println(s1 + " equals " + s2 + " -> "
                + s1.equals(s2));
        System.out.println(s1 + " equals " + s3 + " -> "
                + s1.equals(s3));
        System.out.println(s1 + " equals " + s4 + " -> "
                + s1.equals(s4));
        System.out.println(s1 + " equalsIgnoreCase " + s4 + " -> "
                + s1.equalsIgnoreCase(s4));
    }
}
Hello equals Hello -> true
Hello equals Good-bye -> false
Hello equals HELLO -> false
Hello equalsIgnoreCase HELLO -> true

В Java есть String Pool — область памяти (с Java 7 — в куче), где хранятся строковые литералы. Встретив литерал, например "Java", JVM сначала ищет такую строку в пуле и, если она уже есть, возвращает ссылку на существующий объект вместо создания нового.

Конструктор пул не использует: new String("Java") всегда создаёт новый объект в куче.

String Pool в Java: литералы ссылаются на один объект, new String создаёт новый

Следующий пример демонстрирует сравнение строк с помощью == и метода equals():

public class EqualStrings {
    public static void main(String[] args) {
        String s1 = "Java";
        String s2 = "Java";
        String s3 = new String("Java");
        String s4 = new String(s1);
        System.out.println("s1==s2 : " + (s1 == s2));
        System.out.println("s3==s4 : " + (s3 == s4));
        System.out.println("s1==s3 : " + (s1 == s3));
        System.out.println("s1 equals s2 : " + s1.equals(s2));
        System.out.println("s1 equals s3 : " + s1.equals(s3));
    }
}
s1==s2 : true
s3==s4 : false
s1==s3 : false
s1 equals s2 : true
s1 equals s3 : true

Что выведет этот код? В пул автоматически попадают только литералы и константы времени компиляции. Строка, склеенная во время выполнения, — это новый объект, даже если её текст совпадает с литералом:

public class StringPoolQuiz {
    public static void main(String[] args) {
        String a = "Java";

        String part = "Ja";
        String b = part + "va";          // склейка во время выполнения

        final String constPart = "Ja";
        String c = constPart + "va";     // константа времени компиляции

        System.out.println(a == b);          // Вывод: false
        System.out.println(a == c);          // Вывод: true
        System.out.println(a == b.intern()); // Вывод: true
        System.out.println(a.equals(b));     // Вывод: true
    }
}

Метод intern() возвращает строку из пула с тем же содержимым (и помещает её туда, если её там ещё нет).

Важно

Не сравнивайте строки через ==. Код может «работать» на литералах и ломаться на строках, прочитанных из файла, введённых с клавиатуры или собранных во время выполнения. Для сравнения текста всегда используйте equals().

Сравнение подстрок: startsWith(), endsWith(), contains()

Чтобы проверить часть строки, в классе String есть методы startsWith(), endsWith(), contains() и regionMatches(). Все они возвращают boolean и учитывают регистр символов.

  • Метод startsWith() проверяет, начинается ли строка с префикса, переданного в параметре.
  • Метод endsWith() проверяет, заканчивается ли строка переданным суффиксом.
  • Метод contains() проверяет, входит ли подстрока в строку.
  • Метод regionMatches() сравнивает фрагмент исходной строки с фрагментом в строке-параметре.

Рассмотрим пример:

public class StringExample5 {
    public static void main(String[] args) {
        System.out.println("Foobar".endsWith("bar"));      // Вывод: true
        System.out.println("Foobar".startsWith("Foo"));    // Вывод: true
        System.out.println("Foobar".contains("oo"));       // Вывод: true
        // 3 символа с индекса 6 строки ("wor") против 3 символов "world" с индекса 0 ("wor")
        System.out.println("Hello world!!!".regionMatches(6, "world", 0, 3)); // Вывод: true
        System.out.println("Foobar".startsWith("foo"));    // Вывод: false (регистр)
    }
}

Метод compareTo()

Метод compareTo(str) сравнивает строки лексикографически (посимвольно по кодам Unicode) и возвращает число: меньше нуля — вызывающая строка меньше str, больше нуля — больше, ноль — строки равны. Он нужен для сортировки, где мало знать, равны ли строки.

Возвращается разность кодов первых несовпадающих символов, а если одна строка — начало другой, то разность длин:

System.out.println("a".compareTo("b"));               // Вывод: -1
System.out.println("apple".compareTo("app"));         // Вывод: 2
System.out.println("Java".compareTo("java"));         // Вывод: -32 ('J' = 74, 'j' = 106)
System.out.println("Java".compareToIgnoreCase("java")); // Вывод: 0

Следующий пример сортирует массив строк простой сортировкой обменом на основе compareTo(). В реальном коде так же сработает одна строка Arrays.sort(array).

import java.util.Arrays;

public class SortString {
    private static String[] array = {
            "Для", "работы", "со", "строками", "в", "языке",
            "используются", "классы", "Java", "String", "StringBuilder", "StringBuffer"
    };

    public static void main(String[] args) {
        for (int j = 0; j < array.length; j++) {
            for (int i = j + 1; i < array.length; i++) {
                if (array[i].compareTo(array[j]) < 0) {
                    String t = array[j];
                    array[j] = array[i];
                    array[i] = t;
                }
            }
        }
        System.out.println(Arrays.toString(array));
    }
}
[Java, String, StringBuffer, StringBuilder, Для, в, используются, классы, работы, со, строками, языке]

Обратите внимание на порядок: латинские буквы идут раньше кириллицы, а заглавные — раньше строчных, поэтому «Для» оказалось перед «в». Так получается потому, что compareTo() сравнивает коды символов, а не алфавит конкретного языка. Для сортировки «по-человечески» используют compareToIgnoreCase() или java.text.Collator.

Извлечение символов: метод charAt()

Метод charAt(index) возвращает символ (char) строки по индексу; нумерация начинается с 0, последний символ имеет индекс length() - 1. При индексе вне этого диапазона выбрасывается StringIndexOutOfBoundsException.

public class StringExample3 {
    public static void main(String[] args) {
        char ch = "abc".charAt(1);
        System.out.println(ch);              // Вывод: b

        System.out.println("abc".charAt(3)); // StringIndexOutOfBoundsException
    }
}

Поиск подстроки или символа: indexOf(), lastIndexOf()

Для поиска символа или подстроки в строке Java используются два метода: indexOf() ищет первое вхождение, lastIndexOf() — последнее. Оба возвращают индекс найденного символа или начала подстроки, а если ничего не найдено, — -1.

Чтобы найти первое или последнее вхождение символа, применяйте:

int indexOf(int ch)
int lastIndexOf(int ch)

Здесь ch — символ, который нужно найти (тип int, поэтому можно передать char). Чтобы найти первое или последнее вхождение подстроки, применяйте:

int indexOf(String str)
int lastIndexOf(String str)

Начальную позицию поиска можно указать вторым параметром. lastIndexOf() при этом ищет назад от startIndex:

int indexOf(int ch, int startIndex)
int lastIndexOf(int ch, int startIndex)
int indexOf(String str, int startIndex)
int lastIndexOf(String str, int startIndex)

Рассмотрим применение этих методов на следующем примере:

public class IndexOfExample {
    public static void main(String[] args) {
        String s = "Для работы со строками в языке Java используются "
                + "классы String, StringBuilder, StringBuffer.";

        System.out.println(s);
        System.out.println("indexOf(S) = "
                + s.indexOf('S'));
        System.out.println("lastIndexOf(r) = "
                + s.lastIndexOf('r'));
        System.out.println("indexOf(String) = "
                + s.indexOf("String"));
        System.out.println("lastIndexOf(String) = "
                + s.lastIndexOf("String"));
        System.out.println("indexOf(S, 60) = "
                + s.indexOf('S', 60));
        System.out.println("lastIndexOf(S, 70) = "
                + s.lastIndexOf('S', 70));
        System.out.println("indexOf(Kotlin) = "
                + s.indexOf("Kotlin"));
    }
}
Для работы со строками в языке Java используются классы String, StringBuilder, StringBuffer.
indexOf(S) = 56
lastIndexOf(r) = 90
indexOf(String) = 56
lastIndexOf(String) = 79
indexOf(S, 60) = 64
lastIndexOf(S, 70) = 64
indexOf(Kotlin) = -1

Если нужен только ответ «есть или нет», проще вызвать contains(): s.contains("Java") читается лучше, чем s.indexOf("Java") != -1.

Методы concat(), replace(), toLowerCase(), toUpperCase(), trim()

Эти методы возвращают изменённую копию строки: concat() присоединяет строку в конец, replace() заменяет все вхождения символа или подстроки, toLowerCase() и toUpperCase() переводят строку в нижний или верхний регистр, trim() удаляет пробелы в начале и в конце.

public class ModifyStringExample {
    public static void main(String[] args) {
        System.out.println("Hello".concat(" World"));      // Вывод: Hello World
        System.out.println("Hello".replace('l', 'w'));     // Вывод: Hewwo
        System.out.println("Hello".replace("ll", "LL"));   // Вывод: HeLLo
        System.out.println("Hello".toLowerCase());         // Вывод: hello
        System.out.println("Hello".toUpperCase());         // Вывод: HELLO
        System.out.println("[" + "    Hello World ".trim() + "]");  // Вывод: [Hello World]
        System.out.println("[" + "    Hello World ".strip() + "]"); // Вывод: [Hello World]
    }
}

replace() не работает с регулярными выражениями — для замены по шаблону есть replaceAll() (см. урок Регулярные выражения). Метод strip() (Java 11) похож на trim(), но удаляет и Unicode-пробелы, а trim() — только символы с кодом до U+0020 (пробел).

Неочевидный момент

toLowerCase() и toUpperCase() без аргументов используют локаль по умолчанию. В турецкой локали "TITLE".toLowerCase() вернёт "tıtle" (с i без точки), и сравнение с "title" не пройдёт. Для ключей, команд и идентификаторов пишите toLowerCase(Locale.ROOT).

Преобразование данных: valueOf() и parseInt()

Статический метод String.valueOf() превращает в строку значение любого типа: примитив, массив символов или объект. Обратное преобразование — парсинг строки в число — выполняют методы классов-обёрток: Integer.parseInt(), Long.parseLong(), Double.parseDouble().

Перегруженные версии valueOf() есть для всех типов, например:

static String valueOf(int i)
static String valueOf(double d)
static String valueOf(boolean b)
static String valueOf(Object obj)
static String valueOf(char[] data)
public class ValueOfExample {
    public static void main(String[] args) {
        System.out.println(String.valueOf(42) + 1);   // Вывод: 421 (строка + число)
        System.out.println(String.valueOf(3.5));      // Вывод: 3.5
        System.out.println(String.valueOf(true));     // Вывод: true

        Object obj = null;
        System.out.println(String.valueOf(obj));      // Вывод: null

        int n = Integer.parseInt("42");
        System.out.println(n + 1);                    // Вывод: 43
        double d = Double.parseDouble("2.5");
        System.out.println(d * 2);                    // Вывод: 5.0

        Integer.parseInt("42abc");                    // NumberFormatException
    }
}

В отличие от obj.toString(), вызов String.valueOf(obj) безопасен для null: он вернёт строку "null", а не выбросит NullPointerException.

Метод substring()

Метод substring() возвращает часть строки. У него два варианта: substring(beginIndex) — от указанной позиции до конца и substring(beginIndex, endIndex) — от beginIndex включительно до endIndex не включительно. Длина результата равна endIndex - beginIndex.

public class SubstringExample {
    public static void main(String[] args) {
        System.out.println("Welcome to Kharkiv!!!".substring(11));     // Вывод: Kharkiv!!!
        System.out.println("Welcome to Kharkiv!!!".substring(11, 18)); // Вывод: Kharkiv
        System.out.println("Welcome".substring(7));                    // Вывод: (пустая строка)
        System.out.println("Welcome".substring(8));                    // StringIndexOutOfBoundsException
    }
}

substring(length()) — допустимый вызов, он возвращает пустую строку; исключение возникает только при индексе больше длины строки, отрицательном индексе или beginIndex > endIndex.

Сложение строк: +, concat() и join()

Сложить (конкатенировать) строки в Java можно оператором +, методом concat() или статическим методом String.join(), который появился в JDK 8 и склеивает несколько строк через разделитель. Оператор + удобнее всего: он сам превращает числа, null и объекты в строку.

import java.util.List;

public class StringJoinExample {
    public static void main(String[] args) {
        System.out.println("1" + 2 + 3);   // Вывод: 123
        System.out.println(1 + 2 + "3");   // Вывод: 33

        String s = null;
        System.out.println("Значение: " + s);   // Вывод: Значение: null
        // "Значение: ".concat(s);              // NullPointerException

        String result = String.join(":", "foobar", "foo", "bar");
        System.out.println(result);             // Вывод: foobar:foo:bar

        System.out.println(String.join(", ", List.of("a", "b", "c"))); // Вывод: a, b, c
    }
}

Выражение вычисляется слева направо: в "1" + 2 + 3 сначала получается строка "12", к которой приклеивается 3, а в 1 + 2 + "3" сначала складываются числа. Для многократного сложения в цикле используйте StringBuilder (см. урок StringBuilder и StringBuffer), для форматированной склейки — String.format().

Методы isEmpty() и isBlank()

Метод isEmpty() проверяет, пуста ли строка: он возвращает true, только если её длина равна 0. Метод isBlank() (Java 11) возвращает true, если строка пуста или состоит только из пробельных символов (пробелы, табуляции, переводы строк).

public class StringEmpty {
    public static void main(String[] args) {
        System.out.println("".isEmpty());       // Вывод: true
        System.out.println(" ".isEmpty());      // Вывод: false
        System.out.println(" ".isBlank());      // Вывод: true
        System.out.println("\t\n".isBlank());   // Вывод: true

        String s = null;
        System.out.println(s.isEmpty());       // NullPointerException
    }
}

Ни один из методов не проверяет null, поэтому безопасная проверка «строка не заполнена» выглядит так: s == null || s.isBlank().

Часто задаваемые вопросы

Почему String в Java сделан неизменяемым?

Неизменяемость позволяет безопасно делить одну строку между многими ссылками через String Pool, кэшировать hashCode (поэтому строки хорошо работают ключами HashMap), передавать строки между потоками без синхронизации и не бояться, что имя файла или URL изменят после проверки прав. Как это выглядит в коде — в разделе Неизменяемость String.

Как сравнить строки, если одна из них может быть null?

Используйте Objects.equals(a, b) из java.util — он возвращает true для двух null и не выбрасывает исключение. Если одна сторона — литерал, ставьте его первым: "yes".equals(answer). Разница между == и equals() разобрана в разделе Сравнение строк.

Сколько объектов создаёт new String("Java")?

До двух: литерал "Java" попадает в String Pool (если его там ещё не было), а new всегда создаёт ещё один объект в куче. Если литерал уже есть в пуле, создаётся только один новый объект. Поэтому new String("...") на практике почти не нужен.

Чем length() у строки отличается от length у массива?

У строки длина — метод s.length(), у массива — поле arr.length без скобок. Кроме того, length() считает не буквы, а 16-битные значения char: символ эмодзи занимает два char, поэтому "😀".length() равно 2. Число «настоящих» символов даёт s.codePointCount(0, s.length()).

Как в Java перевести строку в число?

Методами Integer.parseInt("42"), Long.parseLong(), Double.parseDouble(). Если строка не является числом (например, "42abc" или пустая строка), выбрасывается NumberFormatException; пробелы по краям тоже недопустимы, поэтому ввод пользователя сначала обрезают через strip(). Пример — в разделе valueOf() и parseInt().

Practice

Reinforce this lesson with hands-on tasks, each with a level and a time estimate.

All module tasks (7) →

Video Explanation

Prefer video format? Watch this lesson with examples and explanations.

Comments

Please log in or register to have a possibility to add comment.