Возможно, вы уже знакомы с лямбда-выражением, если вы работаете с Javascript или другими языками с неродной типизацией. В этих языках вы можете просто создать лямбда-выражение (аргумент и тело возврата) и обращаться с ним как с переменной (вы можете передать его в методы и аргументы функций). Пример в JS ES6:
// create ES6 anonymous function and use it printer = (t) => console.log(t); printer(“Hello”);
Как сделать то же самое на Java
Java также представила лямбда-выражение с версии 8 с похожим синтаксисом выражений, но разница в том, что каждая переменная в Java имеет тип (собственный или класс/ интерфейс), и все должно оставаться в классе (никаких функций, только методы). Итак, как вы можете догадаться, типом лямбда-выражения является любой интерфейс с одним методом. Вот пример с универсальным типом и методом с произвольным названием accept():
interface MyInterface<T> { void accept(T t); }
Это тип, соответствующий лямбда-функции, которая принимает переменную и что-то с ней делает, ничего не возвращая (void). Давайте сначала реализуем интерфейс не-лямбда-способ вывода значения на консоль:
public class LambdaSample { public static void main(String[] args) { MyInterface<String> printer1 = new MyInterface<String>() { public void accept(String t) { System.out.println(t); } }; printer1.accept("hello"); } }
По сути, мы создали реализацию и запустили ее метод. Эквивалент (но не то же самое с точки зрения байт-кода) с лямбда-выражением Java выглядит следующим образом:
MyInterface<String> printer2 = t -> System.out.println(t); printer2.accept("hello");
В обоих случаях мы создали реализацию, а затем вызвали ее метод, передав аргумент. Метод просто делал то, для чего был реализован (вывод значения).
Примечание 1: MyInterface‹String› — это тип выражения, который может использоваться в методе, например.
private static void methodAcceptingInterface(MyInterface mi) { mi.accept("hello from method"); }
Примечание 2: лямбда-выражение может указывать тип аргумента, а также требовать фигурные скобки и возвращаемый тип, если имеется более одной инструкции. Существует также более короткий синтаксис, который позволяет использовать этот пример, его также можно записать как
Consumer<String> printer = System.out::println
При необходимости обратитесь к документации.
Существующие интерфейсы Java
Как вы могли заметить, написанный нами интерфейс можно повторно использовать для любого другого лямбда-выражения, которое принимает тип и возвращает void. В Java уже есть несколько интерфейсов (называемых функциональными интерфейсами) с разными общими входными и выходными данными (см. список здесь). В этом конкретном случае интерфейс с методом accept(), который ничего не возвращает, называется Consumer и может использоваться вместо нашего интерфейса. Таким образом, весь приведенный выше код может быть записано как:
import java.util.function.Consumer; public class LambdaSample { public static void main(String[] args) { Consumer<String> printer = (String i) -> System.out.println(i); printer.accept("hello"); } }
Пример передачи лямбда-функции собственному методу Java
Метод Collections:removeIf() принимает функциональный интерфейс Predicate‹T› (функциональный интерфейс, принимающий тип и возвращающий логическое значение). Как вы понимаете, этот метод удаляет объект, который возвращает true при передаче в нашу реализацию (выражение lamba) интерфейса. Вот пример, который создает список чисел от 1 до 5 и удаляет четные:
List<Integer> list = Stream.of(1,2,3,4,5) .collect(Collectors.toList()); list.removeIf(i -> i%2 == 0); System.out.println(list); //[1, 3, 5]
Спасибо за прочтение и хлопайте, если полезно