Что такое Lambda-выражения в Java?

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

Они были добавлены в Java 8 (2014 год) и значительно упростили функциональный стиль программирования.

🧠 Что такое lambda-выражение?

Это краткая форма записи однометодного объекта интерфейса (функционального интерфейса). Позволяет писать меньше кода при использовании вместо анонимных классов.

📌 Синтаксис lambda-выражения:

(параметры) -> { тело }

🔍 Примеры:

▶ Пример 1: без параметров

() -> System.out.println("Привет из лямбды!");

▶ Пример 2: с одним параметром

x -> x \* x

▶ Пример 3: с несколькими параметрами и телом

(a, b) -> {
int result = a + b;
return result;
}

✅ Lambda = объект функционального интерфейса

Чтобы использовать lambda-выражение, нужно функциональный интерфейс — интерфейс с одним абстрактным методом.

▶ Пример интерфейса:

@FunctionalInterface
interface MathOperation {
int operation(int a, int b);
}

▶ Использование:

MathOperation add = (a, b) -> a + b;
System.out.println(add.operation(5, 3)); // 8

🔷 Преимущества lambda-выражений:

Преимущество Описание
✅ Краткость Меньше кода по сравнению с анонимными классами
--- ---
✅ Читаемость Более декларативный стиль
--- ---
✅ Функциональность Позволяют использовать функциональный стиль
--- ---
✅ Удобство в коллекциях Используются в Streams, Collections.sort(), forEach()
--- ---

💡 Сравнение: до и после Java 8

🔴 До Java 8 (анонимный класс):

Runnable r = new Runnable() {
public void run() {
System.out.println("Hello");
}
};

✅ После Java 8 (лямбда):

Runnable r = () -> System.out.println("Hello");

🔧 Где применяются lambda-выражения

  1. **Streams API
    **
  2. **Коллекции (sort(), removeIf() и т.д.)
    **
  3. **Functional Interfaces (Predicate, Function, Consumer и т.п.)
    **
  4. **Обработка событий (например, в GUI)
    **

📚 Стандартные функциональные интерфейсы (из java.util.function):

Интерфейс Назначение Пример
Predicate<T> принимает T, возвращает boolean x -> x > 0
--- --- ---
Function<T,R> принимает T, возвращает R x -> x.toString()
--- --- ---
Consumer<T> принимает T, ничего не возвращает x -> System.out.println(x)
--- --- ---
Supplier<T> ничего не принимает, возвращает T () -> "Java"
--- --- ---
BinaryOperator<T> принимает два T, возвращает T (a, b) -> a + b
--- --- ---

🧩 Пример: сортировка списка

List&lt;String&gt; names = Arrays.asList("Аня", "Борис", "Вика");
names.sort((s1, s2) -> s1.compareTo(s2));
names.forEach(name -> System.out.println(name));

🛑 Ограничения и особенности

  • Лямбда-выражения нельзя перегружать — типы должны быть однозначны.

  • Использовать можно только функциональные интерфейсы.

  • В теле лямбды можно использовать только effectively final переменные (неизменяемые).

🧠 Что значит effectively final?

Это переменная, которая не изменяется после присваивания, даже если не помечена как final.

String greeting = "Привет"; // effectively final
Runnable r = () -> System.out.println(greeting); // OK

📌 Разница между ==, equals() и lambda:

  • Lambda — это объект, но он не имеет уникального класса.

  • Лямбды не равны между собой по ==, даже если выглядят одинаково.

  • Нельзя переопределять equals() для сравнения лямбд.

✅ Вывод

Lambda-выражения в Java:

  • Позволяют создавать анонимные функции.

  • Используются вместе с функциональными интерфейсами.

  • Улучшают читаемость и краткость кода.

  • Широко применяются в Stream API и обработке коллекций.

  • Не заменяют полностью классы, но упрощают синтаксис.