Лямбда-выражения
Лямбда-выражения появились в Java 8 и позволяют передавать поведение как значение. Раньше для этого приходилось писать анонимные классы — много шаблонного кода ради одного метода. Лямбда — это компактная запись реализации функционального интерфейса (интерфейса с единственным абстрактным методом).
Лямбды особенно полезны при работе с коллекциями, потоками (Stream API), обработчиками событий и любыми API, которым нужно передать «кусочек кода». В контексте AlashEd — это удобный способ описать действие для каждого датчика или для каждого элемента списка измерений.
Синтаксис
(параметры) -> выражение
(параметры) -> { блок_кода; }
// Примеры форм:
() -> 42 // без параметров
x -> x * 2 // один параметр, скобки можно опустить
(int x, int y) -> x + y // с явными типами
(a, b) -> { return a + b; } // блок с return
Примеры
Пример 1. Замена анонимного класса
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LambdaVsAnonymous {
public static void main(String[] args) {
List<String> sensors = Arrays.asList("ИК", "Ультразвук", "Линия");
// Старый способ:
Collections.sort(sensors, new java.util.Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
});
System.out.println(sensors);
// Новый способ — лямбда:
Collections.sort(sensors, (a, b) -> a.length() - b.length());
System.out.println(sensors);
}
}
Output:
[ИК, Линия, Ультразвук]
[ИК, Линия, Ультразвук]
Пример 2. forEach по коллекции
import java.util.Arrays;
import java.util.List;
public class LambdaForEach {
public static void main(String[] args) {
List<Integer> distances = Arrays.asList(12, 8, 25, 3);
distances.forEach(d -> System.out.println("Расстояние: " + d + " см"));
}
}
Output:
Расстояние: 12 см
Расстояние: 8 см
Расстояние: 25 см
Расстояние: 3 см
Пример 3. Лямбда с блоком кода
import java.util.function.BiFunction;
public class LambdaBlock {
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> avg = (a, b) -> {
int sum = a + b;
return sum / 2;
};
System.out.println("Среднее: " + avg.apply(10, 20));
}
}
Output:
Среднее: 15
Пример 4. Захват переменных из окружения
import java.util.function.IntUnaryOperator;
public class LambdaCapture {
public static void main(String[] args) {
int threshold = 20; // фактически final
IntUnaryOperator clamp = v -> v > threshold ? threshold : v;
System.out.println(clamp.applyAsInt(5));
System.out.println(clamp.applyAsInt(50));
}
}
Output:
5
20
Пример 5. Лямбда как обработчик в Runnable
public class LambdaRunnable {
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> System.out.println("Поток: " + Thread.currentThread().getName());
Thread t = new Thread(task);
t.start();
t.join();
System.out.println("Главный поток завершён");
}
}
Output:
Поток: Thread-0
Главный поток завершён
Подводные камни
Предупреждение
Лямбда может захватывать только эффективно финальные локальные переменные. Попытка изменить захваченную переменную внутри лямбды — ошибка компиляции.
Внутри лямбды
thisссылается на внешний класс, а не на саму лямбду (в отличие от анонимного класса).Лямбда не имеет собственного имени — стек-трейсы у них менее наглядные.
Длинные многострочные лямбды трудно читать — лучше вынести в обычный метод и использовать ссылку на метод.
См. также
Примечание
Материал подготовлен по мотивам Oracle Java Tutorials (Lambda Expressions) и распространяется в рамках Oracle Free Documentation License. Текст написан своими словами, примеры кода — оригинальные.