Лямбда выражения

Лямбда выражения

Лямбда — это функция, которая принимает один аргумент и возвращает значение. Она используется для создания анонимных функций в языке программирования Java. Лямбда выражения позволяют создавать функции без создания отдельного класса или метода. Они используются для обработки коллекций данных, отправки событий в обработчики и других задач. 

Лямбда - это функция, описывающая обработку данных, и оно очень похоже на метод. Однако его можно передавать как аргумент. Существует множество классов, методы которых ожидают именно лямбда-выражения в качестве аргументов. Наиболее распространенные из них реализованы в интерфейсе Stream API

public interface PlainInterface {
String action(int x, int y);
}


public class Main {
public static void main(String[] args) {
PlainInterface plainInterface = new PlainInterface() {
@Override
public String action(int x, int y) {
return String.valueOf(x + y);
}
};
System.out.println(plainInterface.action(2, 5));
}
}


Но давайте сначала перепишем реализацию с использованием лямбда выражения.

public class Main {
public static void main(String[] args) {
PlainInterface plainInterface = (x, y) -> String.valueOf(x - y);
System.out.println(plainInterface.action(5, 3));
}

 

Изменился синтаксис, и код стал проще. Не нужно создавать экземпляр класса, не нужна аннотация оверрайд и, если посмотреть внимательней, мы не передаем типы параметров и не указываем ключевое слово return. Всё это делает компилятор! Ну и если говорить о мелочах, не нужно оборачивать реализацию в фигурные скобки и завершать её точкой с запятой. Однако фигурные скобки, ограничивающие блок кода, не нужны только если реализация умещается в одну строку. Если же вы захотите многострочную реализацию, то и фигурные скобки и return вернутся на свои места. Это чуть больше похоже на классическую реализацию, однако всё же короче и лаконичней! И ещё обращу ваше внимание на новую аннотацию @FunctionalInterface. Она проверяет, является ли интерфейс функциональным, то есть описывает всего один метод. Это обязательно для лямбда выражений и если это не так, аннотация просто не даст коду собраться. 


@FunctionalInterface
public interface PlainInterface {
String action(int x, int y);
}


public static void main(String[] args) {
PlainInterface plainInterface = (x, y) -> {
String str = String.valueOf(x + y);
return str + "!";
};

System.out.println(plainInterface.action(5, 5));

}


А давайте попробуем создать несколько реализаций!

static PlainInterface plainInterface;

public static void main(String[] args) {
plainInterface = (x, y) -> String.valueOf(x + y);
print(5, 5);
plainInterface = (x, y) -> String.valueOf(x - y);
print(5, 5);
plainInterface = (x, y) -> String.valueOf(x * y);
print(5, 5);
}

private static void print(int x, int y) {
System.out.println(plainInterface.action(x, y));
}


Для демонстрации я создал метод print, который выводит в консоль результаты работы нашего лямбда-выражения. В методе print я трижды переопределил поведение лямбда-выражения и трижды вызвал метод print с одинаковыми аргументами. Результаты соответствуют ожидаемому поведению: сумма, разность или произведение. Это простой и наглядный пример переопределения метода plainInterface непосредственно в коде! Давайте теперь изменим код еще немного.

public class Main {
static PlainInterface plainInterface;

static PlainInterface anInterface;
static PlainInterface2 anInterface2;
public static void main(String[] args) {
anInterface = (x, y) -> String.valueOf(x+y);
System.out.println(anInterface.action(5,5));
anInterface2 = Integer::compare;
System.out.println(anInterface2.action(5,15));
}


}
@FunctionalInterface
interface PlainInterface{ String action(int x, int y);}
@FunctionalInterface
interface PlainInterface2{ int action(int x, int y);}

 

Я добавил еще один интерфейс с другой сигнатурой метода и реализовал его по-другому. В этой реализации нет переменных, только имя класса и имя метода, разделенные двумя двоеточиями. Как это работает? Метод compare класса Integer принимает два int параметра и возвращает int значение. Если бы мы описали это с помощью обычного лямбда-выражения, то получили бы следующий код. 


PlainInterface2 interface2 = (x, y) -> Integer.compare(x, y);

 

Мы создали своего рода оболочку для метода compare, и лямбда снова предлагает нам лаконичное решение. Всё, что нам нужно сделать в реализации — это указать имя класса, а через двоеточие — имя метода. Компилятор сам поймёт, что методу нужны два параметра, а мы передаем ему именно два параметра нужных типов, и метод возвращает то, что требует наш функциональный интерфейс. Вот откуда у нас такой простой синтаксис.

Лямбда создаются на основе функциональных интерфейсов и позволяют переопределить поведение непосредственно в коде, упрощая синтаксис. Они значительно облегчают написание кода, делают его короче и понятнее, напоминая нам о синтаксическом сахаре.

Лямбда позволяют использовать преимущества функционального программирования на полностью объектно-ориентированном языке Java.

● Лямбды формируются на основе функционального интерфейса и могут переопределять поведение прямо в коде с упрощенным синтаксисом.

● Лямбды сильно упрощают программирование, делают код проще и короче! И этим напоминают синтаксический сахар.

● Лямбды, являясь функциями, позволяют использовать в полностью объектно-ориентированном языке программирования Java плюсы из функционального программирования. В частности передавать и хранить сами реализации методов!