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

Что такое Lambda функция?

1.2 Junior🔥 301 комментариев
#Основы Java

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

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

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

Lambda функции в Java: синтаксис, использование и лучшие практики

Lambda-функция (λ-функция) — это анонимная функция, которая позволяет писать более компактный и читаемый код. Введена в Java 8 как революционная возможность функционального программирования.

Синтаксис Lambda

// Базовый синтаксис:
(parameter1, parameter2, ...) -> { body }
// или
(parameter) -> statement

// Примеры синтаксиса:

// 1. Без параметров:
() -> System.out.println("Hello");

// 2. Один параметр (скобки опциональны):
x -> x * 2
(x) -> x * 2

// 3. Несколько параметров:
(a, b) -> a + b
(name, age) -> name.length() + age

// 4. С телом:
(x) -> {
    int result = x * 2;
    return result;
}

Functional Interface

Lambda работает только с функциональными интерфейсами (один абстрактный метод):

// ✅ Функциональный интерфейс:
@FunctionalInterface
public interface Calculate {
    int compute(int a, int b); // Один абстрактный метод
}

// Lambda присваивается интерфейсу:
Calculate add = (a, b) -> a + b;
Calculate multiply = (a, b) -> a * b;

System.out.println(add.compute(5, 3)); // 8
System.out.println(multiply.compute(5, 3)); // 15

// ❌ НЕ функциональный интерфейс:
public interface Bad {
    void method1();
    void method2(); // Два метода — нельзя использовать lambda!
}

Built-in Functional Interfaces

Java предоставляет стандартные функциональные интерфейсы:

// 1. Runnable: без параметров, без возврата
Runnable r = () -> System.out.println("Running");
new Thread(r).start();

// 2. Consumer<T>: принимает параметр, ничего не возвращает
Consumer<String> print = s -> System.out.println(s);
print.accept("Hello");

// 3. Function<T, R>: принимает T, возвращает R
Function<Integer, Integer> square = x -> x * x;
System.out.println(square.apply(5)); // 25

// 4. Predicate<T>: принимает T, возвращает boolean
Predicate<Integer> isPositive = x -> x > 0;
System.out.println(isPositive.test(5)); // true

// 5. Supplier<T>: не принимает, возвращает T
Supplier<Double> random = () -> Math.random();
System.out.println(random.get()); // 0.123...

// 6. BiFunction<T, U, R>: два параметра, возврат
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(5, 3)); // 8

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

Пример 1: Фильтрация списка

// Без lambda:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = new ArrayList<>();
for (Integer number : numbers) {
    if (number % 2 == 0) {
        evenNumbers.add(number);
    }
}
System.out.println(evenNumbers); // [2, 4]

// С lambda:
List<Integer> evenNumbers = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());
System.out.println(evenNumbers); // [2, 4]

Пример 2: Трансформация данных

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Без lambda:
List<Integer> lengths = new ArrayList<>();
for (String name : names) {
    lengths.add(name.length());
}

// С lambda:
List<Integer> lengths = names.stream()
    .map(name -> name.length())
    .collect(Collectors.toList());

Пример 3: Сортировка с comparator

List<User> users = Arrays.asList(
    new User("Alice", 30),
    new User("Bob", 25),
    new User("Charlie", 35)
);

// Без lambda:
Collections.sort(users, new Comparator<User>() {
    @Override
    public int compare(User u1, User u2) {
        return Integer.compare(u1.getAge(), u2.getAge());
    }
});

// С lambda:
users.sort((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()));
// или
users.sort(Comparator.comparingInt(User::getAge));

Пример 4: Обработка исключений

List<String> numbers = Arrays.asList("1", "2", "abc", "4");

// Преобразовать в Integer, пропустить невалидные
List<Integer> valid = numbers.stream()
    .map(s -> {
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException e) {
            return null;
        }
    })
    .filter(Objects::nonNull)
    .collect(Collectors.toList());
System.out.println(valid); // [1, 2, 4]

Пример 5: Event Listeners

// Вместо анонимного класса:
button.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick() {
        System.out.println("Button clicked");
    }
});

// Lambda (намного короче):
button.setOnClickListener(() -> System.out.println("Button clicked"));

Method References (сокращение lambda)

Если lambda просто вызывает метод — используй method reference:

// Lambda:
list.forEach(s -> System.out.println(s));

// Method reference (короче и понятнее):
list.forEach(System.out::println);

// Lambda:
users.map(u -> u.getName())

// Method reference:
users.map(User::getName)

// Типы method references:
String::valueOf        // static method
User::getName          // instance method
User::new              // constructor
List::add              // instance method from parameter

Closure: захват переменных

public void demonstrateClosure() {
    int x = 10; // effectively final
    int y = 20; // effectively final
    
    // Lambda захватывает x и y
    Consumer<Integer> consumer = n -> {
        System.out.println(x + y + n);
    };
    
    consumer.accept(5); // 35
    
    // ❌ Ошибка: нельзя менять x после захвата
    // x = 15; // Ошибка компиляции
}

// Правило: переменные, захватываемые lambda, должны быть effectively final

Плюсы Lambda

// 1. Компактность кода
Predicate<String> isEmpty = String::isEmpty;
// vs
Predicate<String> isEmpty = new Predicate<String>() {
    @Override
    public boolean test(String s) {
        return s.isEmpty();
    }
};

// 2. Читаемость с Stream API
numbers.stream()
    .filter(n -> n > 0)
    .map(n -> n * 2)
    .forEach(System.out::println);

// 3. Функциональный стиль
List<Integer> result = users.stream()
    .filter(u -> u.getAge() > 18)
    .map(User::getId)
    .collect(Collectors.toList());

Минусы Lambda

// 1. Сложные lambda сложнее читаются
Predicate<User> isValidUser = u -> 
    u.getName() != null && 
    u.getName().length() > 2 && 
    u.getAge() >= 18 && 
    u.getEmail().contains("@");
// Лучше создать отдельный метод

public boolean isValidUser(User u) {
    return u.getName() != null && 
           u.getName().length() > 2 && 
           u.getAge() >= 18 && 
           u.getEmail().contains("@");
}

// Использовать:
Predicate<User> isValid = this::isValidUser;

// 2. Сложнее дебагить (стек трейс менее информативен)
// 3. Может быть медленнее анонимных классов (хотя обычно нет)

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

// ✅ ИСПОЛЬЗУЙ lambda когда:
// 1. Функциональное преобразование данных
list.map(item -> item.getValue())

// 2. Фильтрация
list.filter(item -> item.isActive())

// 3. Обработка событий
button.onClick(() -> handleClick())

// 4. Callback функции
executor.execute(() -> doWork())

// ❌ НЕ используй lambda когда:
// 1. Логика сложная (больше 2-3 строк)
Function<User, String> getInfo = user -> {
    String name = user.getName();
    int age = user.getAge();
    // ... много логики ...
};
// Лучше создать отдельный метод

// 2. Разная логика для разных случаев
// Используй switch или if-else, не lambda

Рекомендации

// ✅ Хорошо:
users.stream()
    .filter(u -> u.isActive())
    .map(User::getName)
    .collect(Collectors.toList());

// ❌ Плохо (слишком сложная lambda):
users.stream()
    .filter(u -> {
        validateUser(u);
        return u.isActive() && 
               u.getAge() > 18 &&
               checkPermissions(u) &&
               /* еще 10 условий */;
    })
    .collect(Collectors.toList());

// ✅ Правильный подход:
users.stream()
    .filter(this::isValidActiveUser)
    .collect(Collectors.toList());

private boolean isValidActiveUser(User u) {
    validateUser(u);
    return u.isActive() && 
           u.getAge() > 18 &&
           checkPermissions(u);
}

Вывод

Lambda функции — это:

  • Мощный инструмент для функционального программирования
  • Компактный синтаксис для простых операций
  • Неотъемлемая часть Stream API
  • Требуют functional interface (один абстрактный метод)
  • Лучше использовать когда логика простая
  • Комбинировать с method references для максимальной читаемости

Java 8 lambda — это был революционный шаг в эволюции языка, и сегодня без них невозможно представить современный Java код.

Что такое Lambda функция? | PrepBro