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

Author: Tatyana Milkina
  1. Что такое функциональный интерфейс
  2. Лямбда vs анонимные классы
  3. Встроенные функциональные интерфейсы

1. Что такое функциональный интерфейс

Чтобы иметь возможность использовать лямбда выражения, необходим интерфейс:

public interface Searchable {
    boolean test(Car car);
}
Searchable s = (Car c) -> c.getCostUSD() > 20000; 

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

Тип выражения выводится из контекста, в котором используется лямбда выражение. Этот тип называется целевой тип (target type).

Если лямбда выражение присваивается какому-то интерфейсу, лямбда выражение должно соответствовать синтаксису метода интерфейса.

Одно и то же лямбда выражение может использоваться с разными интерфейсами, если они имеют абстрактные методы, которые совместимы. Например:

interface Searchable {
     boolean test(Car car);
}
interface Saleable {
     boolean approve(Car car);
}
//...
Searchable s1 = c -> c.getCostUSD() > 20000;
Saleable s2 = c -> c.getCostUSD() > 20000;

Функциональный интерфейс (functional interface) – это интерфейс у которого только один абстрактный метод. Функциональный интерфейс может содержать любое количество методов по умолчанию (default) или статических методов. Например:

interface A {
     default int defaultMethod() {
         return 0;
     }
     void method();
}

Еще один пример функционального интерфейса:

interface B {
     default int defaultMethod() {
         return 0;
     }
     default int anotherDefaultMethod() {
         return 0;
     }
     void method();
}

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

interface A {
     boolean equals(Object o);
     int hashCode();
     String toString();
     void method();
}

В Java 8 была введена аннотация @FunctionalInterface, которая генерирует ошибку компиляции, если интерфейс не является функциональным:

// This won't compile
@FunctionalInterface 
    interface A {
     void m(int i);
     void m(long l);
}

Примеры функциональных интерфейсов: java.lang.Runnable, java.util.Comparator.

2. Лямбда vs анонимные классы

Лямбда выражения являются альтернативой анонимным классам. Но они не одинаковы.

Общее:

  1. Локальные переменные могут быть использованы только если они final или effective final.
  2. Разрешается доступ к переменным класса и статическим переменным класса.
  3. Они не должны выбрасывать больше исключений чем определено в throws метода функционального интерфейса.

Различия:

  1. Для анонимных классов ключевое слово this ссылается на сам класс. Для лямбды выражений на внешний класс.
  2. Анонимные классы компилируются во внутренние классы. Но лямбда выражения преобразуются в статические private методы класса, в котором они используют invokedynamic инструкцию. Лямбда более эффективны, так как не надо загружать еще один класс.

3. Встроенные функциональные интерфейсы

В Java 8 добавлены встроенные функциональные интерфейсы в пакет java.util.function:

Читайте также:
Комментарии
midavko
Oct 21, 2021
"Разрешается доступ к переменным класса и статическим переменным класса." Если лямда-выражение преобразуется в статический метод класса, тогда он может работаться только со статическими переменными/методами класса. Компилятор выдает ошибку, если попытаться обратиться в лямда-выражении к обычным полям класса. Или я что-то путаю?
sysadmin
Oct 22, 2021
Ошибки компиляции не будет, лямбда выражение действительно может обращаться к нестатическим переменным класса. Почитайте раздел "Lambdas and invokedynamic" на сайте https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood/. Там более подробно описывается как лямбда выражение преобразуется под капотом.