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

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

1. 

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

Predicate<T>, Consumer<T>, Supplier<T>, Function<T, R> и UnaryOperator<T>. От них образованы бинарные и примитивные специализации — всего 43 интерфейса в пакете.

2. 

Для чего нужны бинарные специализации интерфейсов Predicate, Consumer, Function и UnaryOperator?

Интерфейсы Predicate, Consumer, Function и UnaryOperator описывают операцию с одним аргументом. Их бинарные версии принимают два аргумента. Семантика та же, отличается только количество параметров.

3. 

Как называется бинарная версия интерфейса Consumer и каков её функциональный дескриптор?

BiConsumer<T, U> с дескриптором (T, U) -> void. Абстрактный метод — void accept(T t, U u).

4. 

Как называется бинарная версия интерфейса Function и каков её функциональный дескриптор?

BiFunction<T, U, R> с дескриптором (T, U) -> R. Абстрактный метод — R apply(T t, U u).

5. 

Как называется бинарная версия интерфейса Predicate и каков её функциональный дескриптор?

BiPredicate<T, U> с дескриптором (T, U) -> boolean. Абстрактный метод — boolean test(T t, U u).

6. 

Как называется бинарная версия интерфейса UnaryOperator и каков её функциональный дескриптор?

BinaryOperator<T> с дескриптором (T, T) -> T. Интерфейс наследует BiFunction<T, T, T> и добавляет статические методы minBy() и maxBy().

7. 

Для чего нужны примитивные специализации интерфейсов Predicate, Consumer, Function, Supplier и UnaryOperator?

Примитивные специализации позволяют избежать операций автоупаковки и распаковки, когда входные или выходные значения примитивны. Обобщения в Java работают только со ссылочными типами, поэтому Consumer<Integer> на каждом вызове создаёт объект-обёртку, а IntConsumer — нет.

8. 

Перепишите пример с использованием примитивной специализации:

Consumer<Integer> ic = i -> System.out.println(++i);
ic.accept(8);
ic.accept(9);
IntConsumer ic = i -> System.out.println(++i);
ic.accept(8);
ic.accept(9);

Автоупаковка int в Integer при каждом вызове больше не выполняется.

9. 

Перечислите примитивные специализации функционального интерфейса Consumer.

IntConsumervoid accept(int)

LongConsumervoid accept(long)

DoubleConsumervoid accept(double)

10. 

Перечислите примитивные специализации интерфейса Function, которые принимают примитив и возвращают обобщённый тип.

IntFunction<R>R apply(int)

LongFunction<R>R apply(long)

DoubleFunction<R>R apply(double)

11. 

Перечислите примитивные специализации интерфейса Function, которые принимают обобщённый тип и возвращают примитив.

ToIntFunction<T>int applyAsInt(T)

ToLongFunction<T>long applyAsLong(T)

ToDoubleFunction<T>double applyAsDouble(T)

12. 

Перечислите примитивные специализации интерфейса Function, которые и принимают, и возвращают примитив.

IntToDoubleFunction, IntToLongFunction

LongToDoubleFunction, LongToIntFunction

DoubleToIntFunction, DoubleToLongFunction

Версий вида IntToIntFunction нет — вместо них используется IntUnaryOperator.

13. 

Перечислите примитивные специализации функционального интерфейса Supplier.

BooleanSupplierboolean getAsBoolean()

IntSupplierint getAsInt()

LongSupplierlong getAsLong()

DoubleSupplierdouble getAsDouble()

Это единственное семейство, где есть специализация для boolean.

14. 

Перечислите примитивные специализации функционального интерфейса UnaryOperator.

IntUnaryOperatorint applyAsInt(int)

LongUnaryOperatorlong applyAsLong(long)

DoubleUnaryOperatordouble applyAsDouble(double)

У всех трёх есть default-методы compose() и andThen() и статический identity().

15. 

Перечислите примитивные специализации функционального интерфейса BinaryOperator.

IntBinaryOperatorint applyAsInt(int, int)

LongBinaryOperatorlong applyAsLong(long, long)

DoubleBinaryOperatordouble applyAsDouble(double, double)

16. 

Перечислите примитивные специализации функционального интерфейса BiConsumer.

ObjIntConsumer<T>void accept(T, int)

ObjLongConsumer<T>void accept(T, long)

ObjDoubleConsumer<T>void accept(T, double)

Первый аргумент остаётся объектным, примитивным становится только второй.

17. 

Перечислите примитивные специализации функционального интерфейса BiFunction.

ToIntBiFunction<T, U>int applyAsInt(T, U)

ToLongBiFunction<T, U>long applyAsLong(T, U)

ToDoubleBiFunction<T, U>double applyAsDouble(T, U)

Примитивным здесь становится только результат, оба аргумента остаются обобщёнными.

18. 

Перечислите примитивные специализации функционального интерфейса Predicate. Есть ли примитивная версия у BiPredicate?

IntPredicateboolean test(int)

LongPredicateboolean test(long)

DoublePredicateboolean test(double)

У BiPredicate примитивных специализаций нет: интерфейсов вида IntBiPredicate или ObjIntPredicate в пакете не существует.

19. 

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

Имена строятся по шаблону:

Int / Long / Double в начале — тип входного параметра: IntPredicateboolean test(int).

To + тип — тип возвращаемого значения: ToIntFunction<T>int applyAsInt(T).

Тип + To + тип — примитивны и вход, и выход: IntToDoubleFunctiondouble applyAsDouble(int).

Obj + тип — объект плюс примитив: ObjIntConsumer<T>void accept(T, int).

Bi в начале — два объектных аргумента: BiFunction<T, U, R>R apply(T, U).

UnaryOperator / BinaryOperator — все типы совпадают: IntBinaryOperatorint applyAsInt(int, int).

Если результат примитивный, к имени метода добавляется суффикс As + тип: applyAsInt, getAsDouble. У test() и accept() суффикса нет — их результат и так фиксирован.

20. 

Лямбды каких функциональных интерфейсов ожидают методы Stream и IntStream: mapToInt(), map(), mapToObj(), filter(), forEach(), reduce()?

Stream<T>.mapToInt()ToIntFunction<T>, переход к IntStream.

IntStream.map()IntUnaryOperator.

IntStream.mapToObj()IntFunction<R>, возврат к Stream<R>.

IntStream.filter()IntPredicate.

IntStream.forEach()IntConsumer.

IntStream.reduce()IntBinaryOperator.

Дополнительно: Map.forEach() ждёт BiConsumer<K, V>, Map.merge()BiFunction<V, V, V>, List.replaceAll()UnaryOperator<E>.

21. 

Для каких примитивных типов существуют специализации и наследуют ли они обобщённые интерфейсы?

Специализации есть только для int, long и double (плюс BooleanSupplier для boolean). Для float, byte, short и char отдельных интерфейсов нет — используются int- и double-версии с расширяющим преобразованием.

Примитивные специализации не наследуют обобщённые интерфейсы: IntPredicate не является наследником Predicate<Integer>, а IntBinaryOperator — наследником BiFunction. Это независимые типы, присвоить переменную одного другому нельзя.

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