Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Шаблоны в instanceof

Сопоставление с образцом (pattern matching) — способ одновременно проверить, подходит ли значение под какую-то форму, и сразу достать из него нужные части. В Java оно появилось постепенно, и первый шаг — шаблоны в операторе instanceof, доступные с Java 16.

Как было раньше

Оператор instanceof проверяет, принадлежит ли объект типу. Но после проверки объект всё равно приходилось вручную приводить к типу — писать название типа в скобках:

void main() {
    Object value = "Привет";
 
    if (value instanceof String) {
        String text = (String) value;
        IO.println(text.length());
    }
}

Результат:

6

Тип String здесь упомянут трижды, хотя проверка одна.

Шаблон типа

С шаблоном проверка и приведение объединяются: после типа пишут имя новой переменной. Если проверка прошла, переменная уже имеет нужный тип:

void main() {
    Object value = "Привет";
 
    if (value instanceof String text) {
        IO.println(text.length());
    }
}

Результат:

6

Запись String text называется шаблоном типа, а text — переменной шаблона. Она появляется, только если объект действительно оказался строкой.

Разные типы

Шаблоны особенно удобны, когда значение может быть разных типов и с каждым нужно поступить по-своему:

String describe(Object value) {
    if (value instanceof Integer number) {
        return "целое число, в два раза больше: " + number * 2;
    } else if (value instanceof String text) {
        return "строка из " + text.length() + " символов";
    } else if (value instanceof List<?> list) {
        return "список из " + list.size() + " элементов";
    }
    return "что-то другое";
}
 
void main() {
    IO.println(describe(21));
    IO.println(describe("Олег"));
    IO.println(describe(List.of(1, 2, 3)));
    IO.println(describe(3.14));
}

Результат:

целое число, в два раза больше: 42
строка из 4 символов
список из 3 элементов
что-то другое

Для таких цепочек есть ещё более удобный инструмент — шаблоны в switch, о них следующий урок.

Шаблон в условии

Переменную шаблона можно использовать дальше в том же условии после &&: правая часть выполняется, только если левая истинна, а значит, переменная уже есть:

void main() {
    Object input = "  ";
 
    if (input instanceof String s && !s.isBlank()) {
        IO.println("Непустая строка: " + s);
    } else {
        IO.println("Не строка или пустая строка");
    }
}

Результат:

Не строка или пустая строка

Отрицание

Если проверить «не является ли», переменная шаблона доступна после блока if — при условии, что блок завершает метод. Так удобно отсеивать неподходящие значения в начале метода:

void printUpper(Object value) {
    if (!(value instanceof String text)) {
        IO.println("Нужна строка");
        return;
    }
    IO.println(text.toUpperCase());
}
 
void main() {
    printUpper("анна");
    printUpper(42);
}

Результат:

АННА
Нужна строка

Компилятор понимает: если мы дошли до последней строки, значит, value — строка.

Частая ошибка

С || переменная шаблона недоступна: правая часть выполняется как раз тогда, когда проверка типа не прошла, и переменной нет:

void main() {
    Object value = 10;
 
    if (value instanceof String s || s.isEmpty()) {
        IO.println("Пусто");
    }
}

Результат:

Main.java:4: error: cannot find symbol
    if (value instanceof String s || s.isEmpty()) {
                                     ^
  symbol:   variable s
  location: class Main
1 error
error: compilation failed

Переменная шаблона существует только там, где компилятор точно знает, что проверка прошла. Используйте её после && или внутри блока if.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.