Любой разработчик Java во всем мире использовал бы по крайней мере один из следующих интерфейсов: java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator, java.util.concurrent.Callable. Среди заявленных интерфейсов есть некоторая общая особенность, и у них есть только один метод, объявленный в их определении интерфейса. В JDK таких интерфейсов гораздо больше, а также больше, созданных разработчиками Java. Эти интерфейсы также называются интерфейсами S- единого абстрактного метода (интерфейсы SAM). И популярным способом их использования является создание классов Anonymous Inner с использованием этих интерфейсов, что-то вроде:
01
02
03
04
05
06
07
08
09
10
|
public class AnonymousInnerClassTest { public static void main(String[] args) { new Thread( new Runnable() { @Override public void run() { System.out.println( 'A thread created and running ...' ); } }).start(); } } |
В Java 8 та же концепция интерфейсов SAM воссоздается и называется функциональными интерфейсами. Они могут быть представлены с использованием лямбда-выражений , ссылок на методы и ссылок на конструкторы (я расскажу об этих двух темах в следующих публикациях в блоге) Введена аннотация @FunctionalInterface, которую можно использовать для ошибок уровня компилятора, когда аннотированный интерфейс не является допустимым функциональным интерфейсом. Давайте попробуем взглянуть на простой функциональный интерфейс только с одним абстрактным методом:
1
2
3
4
|
@FunctionalInterface public interface SimpleFuncInterface { public void doWork(); } |
Интерфейс также может объявлять абстрактные методы из класса java.lang.Object, но все же интерфейс может быть вызван как функциональный интерфейс:
1
2
3
4
5
6
|
@FunctionalInterface public interface SimpleFuncInterface { public void doWork(); public String toString(); public boolean equals(Object o); } |
Как только вы добавите другой абстрактный метод в интерфейс, компилятор / IDE отметит его как ошибку, как показано на скриншоте ниже:
Интерфейс может расширять другой интерфейс, и в случае, если Интерфейс расширяется функционально и не объявляет никаких новых абстрактных методов, тогда новый интерфейс также функционален. Но интерфейс может иметь один абстрактный метод и любое количество стандартных методов, и интерфейс все равно будет называться функциональным интерфейсом. Чтобы получить представление о методах по умолчанию, пожалуйста, прочитайте здесь .
1
2
3
4
5
6
7
8
9
|
@FunctionalInterface public interface ComplexFunctionalInterface extends SimpleFuncInterface { default public void doSomeWork(){ System.out.println( 'Doing some work in interface impl...' ); } default public void doSomeOtherWork(){ System.out.println( 'Doing some other work in interface impl...' ); } } |
Вышеуказанный интерфейс все еще является действующим функциональным интерфейсом. Теперь давайте посмотрим, как мы можем использовать лямбда-выражение по сравнению с анонимным внутренним классом для реализации функциональных интерфейсов:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
/* * Implementing the interface by creating an * anonymous inner class versus using * lambda expression. */ public class SimpleFunInterfaceTest { public static void main(String[] args) { carryOutWork( new SimpleFuncInterface() { @Override public void doWork() { System.out.println( 'Do work in SimpleFun impl...' ); } }); carryOutWork(() -> System.out.println( 'Do work in lambda exp impl...' )); } public static void carryOutWork(SimpleFuncInterface sfi){ sfi.doWork(); } } |
И результат будет …
1
2
|
Do work in SimpleFun impl... Do work in lambda exp impl... |
Если вы используете IDE, которая поддерживает синтаксис Java-лямбда-выражений ( сборки Netbeans 8 Nightly ), то при использовании анонимного внутреннего класса это дает подсказку, как описано выше:
Это было краткое введение в концепцию функциональных интерфейсов в Java 8, а также о том, как их можно реализовать с помощью лямбда-выражений.
Ссылка: Введение в функциональные интерфейсы — концепция, воссозданная в Java 8 от нашего партнера по JCG Мохамеда Санаулла в блоге Experiences Unlimited .