Урок 15

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


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;

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

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

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

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

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

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

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

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

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

Пример 4. Использование аннотации @FunctionalInterface

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

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

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

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

Общее:

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

Различия:

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

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

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

  • Predicate
  • Consumer
  • Function
  • Supplier
  • UnaryOperator

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



0 comments
Leave your comment: