Лямбда-выражения, появившиеся в Java 8, значительно упростили написание кода, особенно при работе с функциональными интерфейсами. Они позволяют передавать функции в качестве аргументов, сокращают объем кода и делают его более читаемым. В этой статье мы разберем синтаксис лямбда-выражений, их связь с функциональными интерфейсами и примеры использования.
Синтаксис лямбда-выражений
Базовая форма
Лямбда-выражение состоит из:
- Списка параметров (в скобках или без).
- Стрелки ->.
- Тела (выражение или блок кода).
Общий вид:
(параметры) -> { тело }
Варианты синтаксиса
1. Без параметров
Используются пустые скобки:
() -> System.out.println("Hello, World!");
2. Один параметр
Скобки можно опустить:
x -> x * x;
3. Несколько параметров
Обязательны скобки:
(a, b) -> a + b;
4. Указание типов параметров
Типы можно указать явно:
(int x, int y) -> x + y;
Тело лямбда-выражения
- Простое тело (одна строка):
Фигурные скобки и return не требуются:
(String s) -> s.length();
- Блочное тело (несколько операторов):
Используются фигурные скобки и явный return:
(x, y) -> {
int sum = x + y;
return sum;
};
Функциональные интерфейсы
Лямбда-выражения работают с функциональными интерфейсами — интерфейсами с одним абстрактным методом. Примеры:
1. Runnable (метод run()):
Runnable task = () -> System.out.println("Task executed");
2. Comparator<T> (метод compare(T o1, T o2)):
Comparator<Integer> comp = (a, b) -> a - b;
3. Собственный интерфейс:
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
Calculator add = (a, b) -> a + b;
Примеры использования
1. Со Stream API
Лямбды активно используются для обработки коллекций:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
// Фильтрация и вывод
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(System.out::println); // 2, 4
// Преобразование элементов
List<Integer> squares = numbers.stream()
.map(x -> x * x)
.collect(Collectors.toList());
2. Обработка событий
В GUI-приложениях (например, Swing):
button.addActionListener(e -> System.out.println("Кнопка нажата!"));
Захват переменных
Лямбды могут использовать переменные из внешней области видимости, если они effectively final (не изменяются после инициализации):
int threshold = 10;
list.forEach(x -> {
if (x > threshold) { // Захватывается переменная threshold
System.out.println(x);
}
});
Ссылки на методы
Лямбды можно заменять ссылками на методы для еще большей краткости:
- Статический метод: ClassName::method.
- Метод экземпляра: instance::method.
- Конструктор: ClassName::new.
Пример:
List<String> words = Arrays.asList("a", "b", "c");
words.forEach(System.out::println); // Эквивалентно x -> System.out.println(x)
Ограничения и ошибки
1. Несовместимость с функциональными интерфейсами
Лямбда должна соответствовать сигнатуре метода интерфейса:
// Ошибка: метод ожидает два параметра
Calculator invalid = a -> a + 10;
2. Пропуск return в блоке
В блочном теле return обязателен:
(x, y) -> { x + y; }; // Ошибка: нет return
3. Использование не-final переменных:
int count = 0;
Runnable task = () -> count++; // Ошибка: count не effectively final
Заключение
Лямбда-выражения в Java — мощный инструмент для написания лаконичного и выразительного кода. Они упрощают работу с функциональными интерфейсами, Stream API и асинхронными задачами. Понимание их синтаксиса и особенностей позволяет эффективно использовать современные возможности Java, сокращая объем шаблонного кода.
Подписывайтесь:
Телеграм https://t.me/lets_go_code
Канал "Просто о программировании" https://dzen.ru/lets_go_code