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

Что такое pattern matching?

2.0 Middle🔥 121 комментариев
#Основы Java

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

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

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

# Pattern Matching в Java

Pattern Matching — это мощный механизм, добавленный в Java 16 (preview) и 17 (вторая preview) для упрощения работы с условным логикой и деструктуризацией данных. Это замена традиционным instanceof проверкам и switch выражениям.

1. Проблема, которую решает Pattern Matching

Старый способ (до Java 16)

public void processPay(Object obj) {
    // Массивно кода для простой проверки типа
    if (obj instanceof String) {
        String str = (String) obj;  // Явное приведение типа
        System.out.println("String length: " + str.length());
    } else if (obj instanceof Integer) {
        Integer num = (Integer) obj; // Явное приведение типа
        System.out.println("Integer value: " + num);
    } else if (obj instanceof Double) {
        Double d = (Double) obj;     // Явное приведение типа
        System.out.println("Double value: " + d);
    }
}

Новый способ (Java 16+)

public void processPay(Object obj) {
    if (obj instanceof String str) {
        System.out.println("String length: " + str.length()); // Переменная уже создана
    } else if (obj instanceof Integer num) {
        System.out.println("Integer value: " + num);
    } else if (obj instanceof Double d) {
        System.out.println("Double value: " + d);
    }
}

Преимущества:

  • Нет явного приведения типов
  • Переменная создаётся автоматически
  • Меньше кода, больше читаемости

2. Type Pattern (Паттерн типа)

instanceof pattern (Java 16+)

public String describeObject(Object obj) {
    if (obj instanceof String str) {
        return "String: " + str;
    } else if (obj instanceof Integer num) {
        return "Integer: " + num;
    } else if (obj instanceof Double d) {
        return "Double: " + d;
    } else if (obj instanceof Boolean b) {
        return "Boolean: " + b;
    } else {
        return "Unknown type";
    }
}

// Использование
String result = describeObject("Hello");  // String: Hello
result = describeObject(42);               // Integer: 42
result = describeObject(3.14);             // Double: 3.14

Scope переменной

public void checkType(Object obj) {
    if (obj instanceof String str) {
        System.out.println(str); // str доступна
    }
    // System.out.println(str); // ОШИБКА: str недоступна вне блока if
}

// С логическим AND
if (obj instanceof String str && str.length() > 5) {
    System.out.println("Long string: " + str); // str доступна
}

3. Switch Expression Pattern (Java 21+)

Классический switch (раньше)

public String describeShape(Shape shape) {
    switch (shape.getType()) {
        case CIRCLE:
            Circle circle = (Circle) shape;
            return "Circle with radius: " + circle.getRadius();
        case RECTANGLE:
            Rectangle rect = (Rectangle) shape;
            return "Rectangle: " + rect.getWidth() + "x" + rect.getHeight();
        case TRIANGLE:
            Triangle tri = (Triangle) shape;
            return "Triangle with sides: " + tri.getSides();
        default:
            return "Unknown shape";
    }
}

Switch с Pattern Matching (Java 21+)

public String describeShape(Shape shape) {
    return switch (shape) {
        case Circle circle -> "Circle with radius: " + circle.getRadius();
        case Rectangle rect -> "Rectangle: " + rect.getWidth() + "x" + rect.getHeight();
        case Triangle tri -> "Triangle with sides: " + tri.getSides();
        default -> "Unknown shape";
    };
}

Паттерны в switch

record Point(int x, int y) {}

public String describePoint(Point p) {
    return switch (p) {
        case Point(int x, int y) when x == 0 && y == 0 -> "Origin";
        case Point(int x, 0) -> "Point on X axis: " + x;
        case Point(0, int y) -> "Point on Y axis: " + y;
        case Point(int x, int y) -> "Point: (" + x + ", " + y + ")";
    };
}

// Использование
String desc = describePoint(new Point(0, 0));   // Origin
desc = describePoint(new Point(5, 0));          // Point on X axis: 5
desc = describePoint(new Point(3, 4));          // Point: (3, 4)

4. Record Pattern (Java 21+)

Record (неизменяемый класс)

public record User(String name, String email, int age) {}

public void processUser(User user) {
    // Pattern matching на fields record'а
    if (user instanceof User(var name, var email, var age)) {
        System.out.println("Name: " + name);
        System.out.println("Email: " + email);
        System.out.println("Age: " + age);
    }
}

// Вложенные record'ы
public record Address(String street, String city) {}
public record Person(String name, Address address) {}

public String describeAddress(Person person) {
    return switch (person) {
        case Person(var name, Address(var street, var city)) ->
            name + " lives at " + street + ", " + city;
        default -> "Unknown";
    };
}

5. Guard Conditions (Java 17+)

when с instanceof

public String validateValue(Object obj) {
    if (obj instanceof String str && str.length() > 0) {
        return "Non-empty string: " + str;
    } else if (obj instanceof Integer num && num > 0) {
        return "Positive integer: " + num;
    } else if (obj instanceof Integer num && num < 0) {
        return "Negative integer: " + num;
    } else {
        return "Invalid";
    }
}

when в switch (Java 21+)

public String categorize(Object obj) {
    return switch (obj) {
        case String s when s.length() > 10 -> "Long string";
        case String s when s.length() > 0 -> "Short string";
        case Integer i when i > 0 -> "Positive number";
        case Integer i when i < 0 -> "Negative number";
        case Integer i -> "Zero";
        default -> "Unknown";
    };
}

6. Практические примеры

API Response обработка

public sealed interface ApiResponse {}
public record SuccessResponse(String data) implements ApiResponse {}
public record ErrorResponse(int code, String message) implements ApiResponse {}
public record EmptyResponse() implements ApiResponse {}

public void handleApiResponse(ApiResponse response) {
    switch (response) {
        case SuccessResponse(var data) ->
            System.out.println("Success: " + data);
        case ErrorResponse(var code, var message) ->
            System.out.println("Error [" + code + "]: " + message);
        case EmptyResponse() ->
            System.out.println("Empty response");
    };
}

JSON обработка

public Number processNumber(Object obj) {
    return switch (obj) {
        case Integer i when i > 0 -> i * 2;
        case Integer i -> -i;
        case Double d when d > 0 -> d * 2;
        case Double d -> -d;
        case String s -> {
            try {
                yield Double.parseDouble(s);
            } catch (NumberFormatException e) {
                yield 0.0;
            }
        }
        default -> throw new IllegalArgumentException("Unsupported type");
    };
}

Validation chain

public class Validator {
    public boolean validate(Object obj) {
        return obj instanceof String str && isValidEmail(str) ||
               obj instanceof Integer num && isValidAge(num) ||
               obj instanceof Boolean b && b;
    }
    
    private boolean isValidEmail(String email) {
        return email.contains("@");
    }
    
    private boolean isValidAge(Integer age) {
        return age >= 18 && age <= 120;
    }
}

7. История и версии

ВерсияЧто добавилось
Java 16instanceof with pattern (preview)
Java 17instanceof pattern (finalized)
Java 18switch patterns (preview)
Java 19record patterns (preview), switch patterns (preview)
Java 20record patterns (second preview), switch patterns (second preview)
Java 21switch patterns (finalized), record patterns (preview)

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

Используйте Pattern Matching для:

  • Проверки типов объектов
  • Деструктуризации данных (особенно record'ов)
  • Условной логики на основе типов
  • Замены множества instanceof и cast

Не используйте для:

  • Простых boolean проверок
  • Логики, которая должна быть в отдельных методах

9. Альтернативы и сравнение

// Способ 1: Старый instanceof с cast
if (obj instanceof String) {
    String str = (String) obj;
    process(str);
}

// Способ 2: Pattern Matching (Java 16+)
if (obj instanceof String str) {
    process(str);
}

// Способ 3: Strategy Pattern (если много логики)
strategy.process(obj);

// Способ 4: Visitor Pattern (для сложных иерархий)
obj.accept(visitor);

Заключение

Pattern Matching — это революционная возможность в Java для упрощения кода и повышения его читаемости. Особенно мощна в комбинации с records и switch expression'ами. В Java 21+ это уже finalized feature и рекомендуется использовать в новых проектах.

Что такое pattern matching? | PrepBro