Что такое лямбда-выражение (лямбда) в Java?

«Что такое лямбда-выражение (лямбда) в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Синтаксис: (параметры) -> { тело выражения } или (параметры) -> выражение.

Простой пример:

// Без лямбды (анонимный класс)
Runnable oldRunnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
};

// С лямбдой
Runnable newRunnable = () -> System.out.println("Hello");

Примеры с разными функциональными интерфейсами:

// Predicate<T> - проверяет условие
Predicate<String> isEmpty = s -> s == null || s.trim().isEmpty();
boolean test = isEmpty.test(""); // true

// Function<T,R> - преобразует объект
Function<String, Integer> stringToLength = str -> str.length();
int len = stringToLength.apply("Java"); // 4

// Consumer<T> - потребляет объект (выполняет действие)
Consumer<String> printer = message -> System.out.println("Log: " + message);
printer.accept("Test"); // Вывод: Log: Test

// Supplier<T> - поставляет объект
Supplier<Double> randomSupplier = () -> Math.random();
double val = randomSupplier.get();

Использование со Streams API (типичный кейс):

List<String> names = Arrays.asList("Anna", "Bob", "Alice");
// Фильтрация и преобразование с помощью лямбд
List<String> result = names.stream()
        .filter(name -> name.startsWith("A")) // Predicate
        .map(String::toUpperCase)            // Method reference (частный случай лямбды)
        .collect(Collectors.toList());       // ["ANNA", "ALICE"]

Ключевые особенности:

  • Позволяют писать более чистый и компактный код.
  • Не создают новый объект .class файл (в отличие от анонимных классов), что эффективнее.
  • Могут захватывать переменные из окружающего контекста (должны быть effectively final).
  • Являются основой для Streams API и многих современных Java-фреймворков.