Логотип Workflow

Article

Updated at:

Functional Interfaces And Lambdas

Тема 11. Functional Interfaces and Lambdas

Функциональные интерфейсы и лямбды в Java позволяют передавать поведение как значение. Это не замена ООП, а способ писать более гибкий прикладной код: стратегию, фильтр, коллбек, обработчик события. Для новичка главная польза — меньше шаблонного кода и более явные контракты поведения.

Lambda and Functional Interface

1. Базовая идея: SAM-интерфейс

Функциональный интерфейс имеет один абстрактный метод (SAM — Single Abstract Method).

@FunctionalInterface
interface MathOp {
    int apply(int a, int b);
}

MathOp add = (a, b) -> a + b;
System.out.println(add.apply(2, 3)); // 5

Аннотация @FunctionalInterface не обязательна, но полезна: компилятор проверит, что интерфейс действительно SAM.

2. Где это используется в реальной Java

  1. Collections API: sort, removeIf, forEach.
  2. Stream API: map, filter, reduce.
  3. CompletableFuture и асинхронные пайплайны.
  4. Паттерны Strategy/Callback.
  5. Runnable, Callable, ExecutorService.

3. Стандартные functional interfaces

ИнтерфейсКонтракт
Predicate<T>T -> boolean
Function<T, R>T -> R
Consumer<T>T -> void
Supplier<T>() -> T
UnaryOperator<T>T -> T
BinaryOperator<T>(T, T) -> T
BiFunction<T, U, R>(T, U) -> R

Пример:

Predicate<String> longName = s -> s.length() >= 4;
Function<String, String> upper = String::toUpperCase;
Consumer<String> printer = System.out::println;

List.of("ann", "alex").stream()
        .filter(longName)
        .map(upper)
        .forEach(printer);

4. Синтаксис лямбд

() -> 42
x -> x * 2
(a, b) -> a + b
(String s) -> s.trim()
(a, b) -> {
    int r = a + b;
    return r;
}

Правило читаемости: если лямбда становится длинной, лучше вынести её в именованный метод.

5. Method reference как короткая форма

Когда лямбда просто вызывает существующий метод, удобнее method reference:

List<String> names = new ArrayList<>(List.of("Bob", "Ann", "alex"));
names.sort(String::compareToIgnoreCase);

Формы:

  1. ClassName::staticMethod
  2. obj::instanceMethod
  3. ClassName::instanceMethod
  4. ClassName::new

6. Захват переменных и effectively final

Лямбды могут читать локальные переменные, если они final или effectively final:

int min = 3;
Predicate<String> p = s -> s.length() >= min;

Нельзя менять min после захвата:

int min = 3;
min++; // после этого переменная не effectively final

Это ограничение защищает от трудноуловимых ошибок времени жизни и конкуренции.

7. Композиция функций и предикатов

Function<String, String> trim = String::trim;
Function<String, String> upper = String::toUpperCase;
Function<String, String> pipeline = trim.andThen(upper);

System.out.println(pipeline.apply("  java  ")); // JAVA
Predicate<String> notBlank = s -> !s.isBlank();
Predicate<String> shortWord = s -> s.length() <= 5;
Predicate<String> rule = notBlank.and(shortWord);

Композиция делает правила модульными: их проще тестировать и переиспользовать.

8. Прикладные паттерны

Strategy

interface DiscountStrategy {
    double apply(double amount);
}

double checkout(double amount, DiscountStrategy strategy) {
    return strategy.apply(amount);
}

double result = checkout(1000, a -> a * 0.9);

Callback wrapper

void withLogging(String opName, Runnable action) {
    long start = System.nanoTime();
    try {
        action.run();
    } finally {
        System.out.println(opName + " took " + (System.nanoTime() - start));
    }
}

9. Частые ошибки

  1. Лямбда на пол-экрана с тяжелой бизнес-логикой.
  2. Побочные эффекты внутри stream-операций.
  3. Непонятные имена аргументов в сложных выражениях.
  4. Создание своих интерфейсов там, где хватает java.util.function.

10. Когда лучше обычный метод

Выносите код в метод, если:

  1. логика повторяется;
  2. лямбда стала длинной;
  3. нужно отдельное unit-тестирование;
  4. имя метода лучше объясняет намерение, чем inline-лямбда.

Что важно запомнить

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

Авторизуйтесь чтоб пройти тесты

Quiz

Проверьте, что вы усвоили

Practice

Интерактивная практика

Выполните задания и сразу проверьте ответ.