Лямбда-выражения и функциональный интерфейс в Java 8

Лямбда (λ) выражение:

Лямбда-исчисление - это большое изменение в математическом мире, которое было введено в 1930 году. Из-за преимуществ лямбда-исчисления постепенно эти концепции начали использоваться в мире программирования. «LISP» - первая программа, в которой используется лямбда-выражение.

Основная цель λLambda Expression - привнести преимущества функционального программирования в java.

Что такое лямбда-выражение (λ):

Лямбда-выражение - это просто анонимная (безымянная) функция. Это означает, что функция не имеет имени, типа возвращаемого значения и модификаторов доступа.

Лямбда-выражение, также известное как анонимные функции или замыкания.

Пример 1. Обычный метод Java

public void m1 () {
System.out.println («Привет, Java»);
}

Выше обычного метода Java вы можете написать, используя Лямбда-выражение (λ) следующим образом:

() - ›{
sop (« Привет, Java »);
}

or

() - ›{sop (« Привет, Java »); }

or

() - ›sop (« Привет, Java »);

Пример 2: Обычный метод Java с аргументом

public void add (int a, int b) {
System.out.println (a + b);
}

Выше обычного метода Java вы можете написать, используя Лямбда-выражение (λ) следующим образом:

(int a, int b) - ›sop (a + b);

примечание 1: если тип параметра может быть определен компилятором автоматически в зависимости от контекста, мы также можем удалить типы.

примечание 2: указанное выше лямбда-выражение мы можем переписать как (a, b) - ›sop (a + b);

Пример 3: Обычный метод Java с возвратом

общедоступная строка m1 (String str) {
return str;
}

Выше обычного метода Java вы можете написать, используя Лямбда-выражение (λ) следующим образом:

(String str) - ›return str;

or

(ул) - ›ул;

Выводы:

  1. Лямбда-выражение может иметь ноль или более параметров (аргументов).
    Пример:
    () - ›sop (« Hello Java »);
    (int a) - ›sop (a);
    (inta, int b) -› return a + b;
  2. Обычно мы можем указать тип параметра. Если компилятор ожидает тип, основанный на контексте, мы можем удалить тип.
    Пример:
    (int a, int b) - ›sop (a + b);
    (a, b) - ›sop (a + b);
  3. Если присутствует несколько параметров, эти параметры следует разделять запятой (,).
  4. Если доступно нулевое количество параметров, мы должны использовать пустой параметр [like ()]. ​​
    Пример:
    () - ›sop (« Hello Java »);
  5. Если доступен только один параметр и компилятор может ожидать тип, мы также можем удалить тип и круглые скобки.

6. Подобно телу метода, тело лямбда-выражения также может содержать несколько операторов. Если присутствует более одного оператора, мы должны заключить их внутри фигурных скобок. если присутствует один оператор, то фигурные скобки необязательны.

После того, как мы напишем лямбда-выражение, мы сможем вызывать это выражение как метод, поскольку для этого требуются функциональные интерфейсы.

Функциональные интерфейсы:

если интерфейс содержит только один абстрактный метод, такой тип интерфейсов называется функциональными интерфейсами, а метод называется функциональным методом или одним абстрактным методом (SAM).
Пример:
1) Runnable: он содержит только run ()
2) Comparable: он содержит только метод compareTo ()
3) ActionListener: он содержит только actionPerformed ()
4) Callable: он содержит только метод call ()

Внутри функционального интерфейса в дополнение к одному абстрактному методу (SAM) мы можем написать любое количество стандартных и статических методов.

В Java 8 SunMicroSystem представила аннотацию @FunctionalInterface, чтобы указать, что интерфейс является FunctionalInterface.

InsideFunctionalInterface мы можем взять только один абстрактный метод, если мы возьмем более одного абстрактного метода, то мы получим ошибку компиляции.

Внутри FunctionalInterface мы должны использовать только один абстрактный метод. Если мы не объявляем этот абстрактный метод, компилятор выдает сообщение об ошибке.

FunctionalInterface относительно наследования:
Если интерфейс расширяет FunctionalInterface, а дочерний интерфейс не содержит никаких абстрактных методов, то дочерний интерфейс также является FunctionalInterface.

В дочернем интерфейсе мы можем определить точно такой же абстрактный метод родительского интерфейса.

В дочернем интерфейсе мы не можем определять какие-либо новые абстрактные методы, иначе дочерний интерфейс не будет FunctionalInterface, и если мы пытаемся использовать аннотацию @FunctionalInterface, компилятор выдает сообщение об ошибке.

Функциональный интерфейс и лямбда-выражения:

После того, как мы напишем лямбда-выражения для вызова его функциональности, потребуется FunctionalInterface. Мы можем использовать ссылку FunctionalInterface для ссылки на лямбда-выражение. Везде, где применима концепция FunctionalInterface, мы можем использовать лямбда-выражения.

Пример 1. Без лямбда-выражения (λ):

Код выше с лямбда-выражением (λ):

Пример 2: Без лямбда-выражения (λ):

Код выше с Лямбда-выражением (λ):

Анонимные внутренние классы против лямбда-выражений

Везде, где мы используем анонимные внутренние классы, возможно использование лямбда-выражения для уменьшения длины кода и устранения сложности.

Пример с анонимным внутренним классом:

Пример выше с лямбда-выражением (λ):

В чем преимущества лямбда-выражения?

  1. Мы можем уменьшить длину кода, чтобы улучшить читаемость кода.
  2. Мы можем решить сложность анонимных внутренних классов.
  3. Мы можем предоставить лямбда-выражение вместо объекта.
  4. Мы можем передать лямбда-выражение в качестве аргумента методам.

Примечание.

  1. Анонимный внутренний класс может расширять конкретный класс, может расширять абстрактный класс, может реализовывать интерфейс с любым количеством методов, но
  2. Лямбда-выражение может реализовать интерфейс только с одним абстрактным
    методом (FunctionalInterface).
  3. Следовательно, если анонимный внутренний класс реализует функциональный интерфейс в этом конкретном случае, только мы можем заменить его лямбда-выражениями. Следовательно, везде, где присутствует концепция анонимного внутреннего класса, может быть невозможно заменить лямбда-выражениями.
  4. Анонимный внутренний класс! = Лямбда-выражение
  5. Внутри анонимного внутреннего класса мы можем объявлять переменные экземпляра.
  6. Внутри анонимного внутреннего класса «this» всегда ссылается на текущий объект внутреннего класса (анонимный внутренний класс), но не на связанный объект внешнего класса.

Пример

  1. Внутри лямбда-выражения мы не можем объявлять переменные экземпляра.
  2. Все, что переменные объявляют внутри лямбда-выражения, просто действует как локальные переменные.
  3. В лямбда-выражении ключевое слово this представляет текущую ссылку на объект внешнего класса (то есть текущую ссылку на включающий класс, в котором мы объявляем лямбда-выражение)

примечание:

  1. Из лямбда-выражения мы можем напрямую обращаться к включающим переменным класса и включающим переменным метода.
  2. Локальные переменные, на которые ссылается лямбда-выражение, неявно являются окончательными, и поэтому мы не можем выполнить повторное присвоение этих локальных переменных, иначе мы получим ошибку времени компиляции

Различия между анонимными внутренними классами и лямбда-выражением: