Что такое лямбда-выражение (лямбда) в 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-фреймворков.

Ответ 18+ 🔞

Да ты посмотри, что эти умники в Java 8 придумали! Лямбды, блядь. Ну, а че, удобно, если честно. Раньше, сука, чтобы функцию как объект передать, надо было анонимный класс городить, строчек на десять, а теперь — раз, и в одну строку.

Лямбда, если по-простому, — это короткий способ написать кусок кода, который делает одно действие. Типа функции, но без лишнего официоза. Работает только с функциональными интерфейсами — это такие интерфейсы, где всего один абстрактный метод. Ну, типа Runnable, Comparator и прочая хуйня.

Как выглядит? Да элементарно: (параметры) -> { тело } или даже (параметры) -> выражение.

Вот смотри, как было и как стало:

// Раньше, блядь, вот эта поебень:
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"); // Выведет в консоль эту хуйню

// Supplier<T> — просто поставляет что-то, типа фабрика
Supplier<Double> randomSupplier = () -> Math.random();
double val = randomSupplier.get(); // Случайное число, вот и вся магия

А самое охуенное — это когда со Streams API используешь. Вот тут они реально раскрываются:

List<String> names = Arrays.asList("Anna", "Bob", "Alice");
// Отфильтруем имена на "A" и сделаем их большими буквами
List<String> result = names.stream()
        .filter(name -> name.startsWith("A")) // Вот она, лямбда-проверка
        .map(String::toUpperCase)            // А это method reference, родственник лямбды
        .collect(Collectors.toList());       // И собираем обратно в список
// Получится ["ANNA", "ALICE"]

Что в сухом остатке, а?

  • Код становится короче и читабельнее, пиздец как.
  • Не создают кучу лишних .class файлов, как анонимные классы, так что эффективнее.
  • Могут пользоваться переменными снаружи, но только если те фактически финальные (не меняются).
  • Это, блядь, фундамент для всего современного в Java: Streams, Optional, всякие реактивные штуки. Без них теперь никуда, хитрая жопа.

В общем, вещь полезная. Сначала мозг ломается, а потом привыкаешь и без них как без рук.