← Назад к вопросам
Как лямбда связана с функциональным интерфейсом
1.0 Junior🔥 191 комментариев
#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Лямбда и функциональные интерфейсы в Java
Лямбда-выражения и функциональные интерфейсы — революционная функциональность Java 8, которая привнесла функциональное программирование в язык. Это ключевой механизм современной Java разработки.
Что такое функциональный интерфейс?
Функциональный интерфейс — это интерфейс ровно с одним абстрактным методом:
// ✅ Функциональный интерфейс
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
// ✅ Также функциональный интерфейс (без аннотации)
public interface Printer {
void print(String message);
}
// ❌ НЕ функциональный интерфейс (два метода)
public interface Invalid {
void method1();
void method2();
}
// ❌ НЕ функциональный интерфейс (0 методов)
public interface Empty {
}
@FunctionalInterface аннотация:
- Опциональна, но рекомендуется
- Указывает на то, что интерфейс функциональный
- Компилятор проверит наличие ровно одного абстрактного метода
Как лямбда реализует функциональный интерфейс
Лямбда-выражение — это анонимная реализация функционального интерфейса:
// Определение функционального интерфейса
@FunctionalInterface
public interface Operation {
int execute(int a, int b);
}
// Способ 1: Анонимный класс (старый стиль)
Operation add = new Operation() {
@Override
public int execute(int a, int b) {
return a + b;
}
};
// Способ 2: Лямбда-выражение (новый стиль)
Operation add = (a, b) -> a + b;
// Использование
int result = add.execute(5, 3); // 8
Синтаксис лямбда-выражений
// Синтаксис: (параметры) -> тело
// 1. Без параметров
@FunctionalInterface
interface Greeting {
void greet();
}
Greeting g = () -> System.out.println("Hello!");
// 2. Один параметр (скобки опциональны)
@FunctionalInterface
interface Multiplier {
int multiply(int x);
}
Multiplier m = x -> x * 2;
Multiplier m2 = (x) -> x * 2; // Также правильно
// 3. Несколько параметров
@FunctionalInterface
interface Adder {
int add(int a, int b);
}
Adder add = (a, b) -> a + b;
// 4. Несколько строк кода (требуются скобки)
Adder addVerbose = (a, b) -> {
System.out.println("Adding " + a + " and " + b);
return a + b;
};
// 5. Ссылка на метод
Adder addMethod = Integer::sum;
Встроенные функциональные интерфейсы (java.util.function)
Java предоставляет готовые функциональные интерфейсы:
// 1. Predicate<T> — проверка условия (T -> boolean)
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
// 2. Consumer<T> — потребление значения (T -> void)
Consumer<String> print = System.out::println;
print.accept("Hello");
// 3. Function<T, R> — преобразование (T -> R)
Function<String, Integer> length = s -> s.length();
System.out.println(length.apply("Java")); // 4
// 4. Supplier<T> — поставка значения (void -> T)
Supplier<String> supplier = () -> "Generated value";
System.out.println(supplier.get());
// 5. BiFunction<T, U, R> — функция с двумя параметрами
BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b;
System.out.println(multiply.apply(3, 4)); // 12
// 6. BiConsumer<T, U> — потребление двух значений
BiConsumer<String, Integer> printNTimes = (s, n) -> {
for (int i = 0; i < n; i++) System.out.println(s);
};
Связь между лямбда и интерфейсом
@FunctionalInterface
public interface StringTransformer {
String transform(String input);
}
public class Main {
public static void main(String[] args) {
// Лямбда присваивается переменной типа интерфейса
StringTransformer toUpperCase = s -> s.toUpperCase();
StringTransformer toLowerCase = s -> s.toLowerCase();
StringTransformer reverse = s -> new StringBuilder(s).reverse().toString();
// Использование
System.out.println(toUpperCase.transform("Hello")); // HELLO
System.out.println(toLowerCase.transform("Hello")); // hello
System.out.println(reverse.transform("Hello")); // olleH
}
// Лямбда как параметр функции
static void apply(StringTransformer transformer, String input) {
System.out.println(transformer.transform(input));
}
}
// Вызов
Main.apply(s -> s.toUpperCase(), "hello"); // HELLO
Практические примеры
// Фильтрация списка
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// Преобразование списка
List<String> words = Arrays.asList("Java", "Spring", "Hibernate");
List<Integer> lengths = words.stream()
.map(w -> w.length())
.collect(Collectors.toList());
// Сортировка с лямбда
Collections.sort(words, (a, b) -> a.length() - b.length());
// Обработка элементов
numbers.forEach(n -> System.out.println(n * 2));
// Создание потока с лямбда
new Thread(() -> System.out.println("Running in thread")).start();
// Callback функция
interface DataFetcher {
void onSuccess(String data);
}
void fetchData(DataFetcher callback) {
callback.onSuccess("Data loaded");
}
fetchData(data -> System.out.println("Received: " + data));
Type Inference (Вывод типов)
Компилятор может выводить типы параметров из контекста:
// Компилятор знает, что a и b — int, потому что интерфейс Calculator имеет method(int a, int b)
Calculator calc = (a, b) -> a + b;
// Явное указание типов (опционально)
Calculator calc2 = (int a, int b) -> a + b;
// В Stream API тип выводится из коллекции
List<String> words = Arrays.asList("A", "BB", "CCC");
words.stream().forEach(w -> System.out.println(w)); // w тип String
Лямбда и исключения
@FunctionalInterface
interface Operation {
int execute() throws IOException;
}
// Лямбда может выбросить исключение
Operation op = () -> {
throw new IOException("Error");
};
// Обработка
try {
op.execute();
} catch (IOException e) {
e.printStackTrace();
}
Closure — захват переменных
int multiplier = 5; // Переменная должна быть effectively final
// Лямбда захватывает значение переменной
Function<Integer, Integer> multiply = x -> x * multiplier;
System.out.println(multiply.apply(3)); // 15
// ❌ ОШИБКА: нельзя изменять захваченную переменную
// multiplier = 10; // Compilation error!
Ссылки на методы
Сокращенный синтаксис для лямбда:
// Лямбда
Function<String, Integer> length1 = s -> s.length();
// Ссылка на метод (эквивалентно)
Function<String, Integer> length2 = String::length;
// Другие примеры
Consumer<String> print = System.out::println;
Supplier<List<String>> listSupplier = ArrayList::new;
BiFunction<String, String, Boolean> equals = String::equals;
Таблица типов лямбда
| Интерфейс | Параметры | Возвращает | Пример |
|---|---|---|---|
| Predicate<T> | T | boolean | n -> n > 0 |
| Consumer<T> | T | void | s -> print(s) |
| Function<T,R> | T | R | s -> s.length() |
| Supplier<T> | (none) | T | () -> "value" |
| BiFunction<T,U,R> | T, U | R | (a,b) -> a+b |
| BiConsumer<T,U> | T, U | void | (a,b) -> print(a,b) |
| BiPredicate<T,U> | T, U | boolean | (a,b) -> a.equals(b) |
| UnaryOperator<T> | T | T | x -> x * 2 |
| BinaryOperator<T> | T, T | T | (a,b) -> a+b |