Функциональный интерфейс в Java - Вопросы

Всего: 5 вопросов

1. 

Что такое функциональный интерфейс в Java?

Функциональный интерфейс — это интерфейс ровно с одним абстрактным методом (SAM, Single Abstract Method). Такой интерфейс может быть целевым типом лямбда-выражения или ссылки на метод. Количество default-, static-, private- и private static-методов не ограничено (последние два — с Java 9), а абстрактные объявления, повторяющие public-методы класса Object (equals, hashCode, toString), при подсчёте не учитываются. Примеры из JDK: Runnable, Callable, Comparator, Iterable.

2. 

Что такое функциональный дескриптор (function descriptor)?

Функциональный дескриптор — это сигнатура абстрактного метода функционального интерфейса, то есть форма лямбда-выражения, которое может его реализовать. Записывается как параметры -> тип возвращаемого значения; имя метода в дескриптор не входит. Примеры: у void doSomething() дескриптор () -> void, у int someMethod1(String param)String -> int, у void someMethod2(int a1, int a2)(int, int) -> void, у Consumer<T>T -> void.

3. 

Почему Comparator остаётся функциональным интерфейсом, хотя объявляет два абстрактных метода — compare(T, T) и equals(Object)?

Потому что абстрактные объявления, повторяющие public-методы класса Object, при подсчёте не учитываются. Любой класс, реализующий интерфейс, уже наследует equals, hashCode и toString от Object, поэтому лямбде нечего в них реализовывать — компилятор исключает такие объявления. Фактически абстрактный метод у Comparator один, compare, поэтому аннотация @FunctionalInterface на нём стоит совершенно законно и строка Comparator<Car> byCost = (a, b) -> a.getCostUSD() - b.getCostUSD(); компилируется.

4. 

Что такое целевой тип (target type) лямбда-выражения и откуда он берётся?

Само лямбда-выражение не содержит информации о том, какой интерфейс оно реализует. Тип выводится компилятором из контекста использования и называется целевым типом. Он берётся из объявления переменной (Searchable s = c -> ...;), параметра метода (list.removeIf(c -> ...)), возвращаемого значения метода, приведения типа, тернарного оператора или инициализатора массива. Отсюда следствие: одна и та же лямбда подходит разным интерфейсам, если совпадают список параметров, возвращаемый тип и объявленные исключения (имена абстрактных методов роли не играют). Код без целевого типа не компилируется: var f = () -> System.out.println("hi"); и Object o = c -> c.getCostUSD() > 20000; дают ошибку компиляции.

5. 

Какие готовые функциональные интерфейсы есть в пакете java.util.function?

Основные: Predicate<T> с методом boolean test(T t) — проверка условия; Consumer<T> с void accept(T t) — действие без результата; Function<T, R> с R apply(T t) — преобразование значения; Supplier<T> с T get() — поставка значения без аргументов; UnaryOperator<T> и BinaryOperator<T> — частные случаи Function, у которых аргументы и результат одного типа; двухаргументные BiFunction<T, U, R>, BiPredicate<T, U>, BiConsumer<T, U>. Для примитивов есть специализации без автоупаковки: IntPredicate, IntFunction<R>, ToIntFunction<T>, IntUnaryOperator, IntBinaryOperator, IntSupplier, IntConsumer и их аналоги для long и double. Вне пакета функциональными являются также Runnable, Callable<V>, Comparator<T>, Iterable<T> и AutoCloseable.

Страница 1 из 1