Специализации функциональных интерфейсов в Java - Вопросы
Всего: 21 вопросов
1. Перечислите основные функциональные интерфейсы пакета java.util.function.
Перечислите основные функциональные интерфейсы пакета java.util.function.
Predicate<T>, Consumer<T>, Supplier<T>, Function<T, R> и UnaryOperator<T>. От них образованы бинарные и примитивные специализации — всего 43 интерфейса в пакете.
2. Для чего нужны бинарные специализации интерфейсов Predicate, Consumer, Function и UnaryOperator?
Для чего нужны бинарные специализации интерфейсов Predicate, Consumer, Function и UnaryOperator?
Интерфейсы Predicate, Consumer, Function и UnaryOperator описывают операцию с одним аргументом. Их бинарные версии принимают два аргумента. Семантика та же, отличается только количество параметров.
3. Как называется бинарная версия интерфейса Consumer и каков её функциональный дескриптор?
Как называется бинарная версия интерфейса Consumer и каков её функциональный дескриптор?
BiConsumer<T, U> с дескриптором (T, U) -> void. Абстрактный метод — void accept(T t, U u).
4. Как называется бинарная версия интерфейса Function и каков её функциональный дескриптор?
Как называется бинарная версия интерфейса Function и каков её функциональный дескриптор?
BiFunction<T, U, R> с дескриптором (T, U) -> R. Абстрактный метод — R apply(T t, U u).
5. Как называется бинарная версия интерфейса Predicate и каков её функциональный дескриптор?
Как называется бинарная версия интерфейса Predicate и каков её функциональный дескриптор?
BiPredicate<T, U> с дескриптором (T, U) -> boolean. Абстрактный метод — boolean test(T t, U u).
6. Как называется бинарная версия интерфейса UnaryOperator и каков её функциональный дескриптор?
Как называется бинарная версия интерфейса UnaryOperator и каков её функциональный дескриптор?
BinaryOperator<T> с дескриптором (T, T) -> T. Интерфейс наследует BiFunction<T, T, T> и добавляет статические методы minBy() и maxBy().
7. Для чего нужны примитивные специализации интерфейсов Predicate, Consumer, Function, Supplier и UnaryOperator?
Для чего нужны примитивные специализации интерфейсов Predicate, Consumer, Function, Supplier и UnaryOperator?
Примитивные специализации позволяют избежать операций автоупаковки и распаковки, когда входные или выходные значения примитивны. Обобщения в Java работают только со ссылочными типами, поэтому Consumer<Integer> на каждом вызове создаёт объект-обёртку, а IntConsumer — нет.
8. Перепишите пример с использованием примитивной специализации:
Consumer<Integer> ic = i -> System.out.println(++i);
ic.accept(8);
ic.accept(9);
Перепишите пример с использованием примитивной специализации:
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.
Перечислите примитивные специализации функционального интерфейса Consumer.
IntConsumer — void accept(int)
LongConsumer — void accept(long)
DoubleConsumer — void accept(double)
10. Перечислите примитивные специализации интерфейса Function, которые принимают примитив и возвращают обобщённый тип.
Перечислите примитивные специализации интерфейса Function, которые принимают примитив и возвращают обобщённый тип.
IntFunction<R> — R apply(int)
LongFunction<R> — R apply(long)
DoubleFunction<R> — R apply(double)
11. Перечислите примитивные специализации интерфейса Function, которые принимают обобщённый тип и возвращают примитив.
Перечислите примитивные специализации интерфейса Function, которые принимают обобщённый тип и возвращают примитив.
ToIntFunction<T> — int applyAsInt(T)
ToLongFunction<T> — long applyAsLong(T)
ToDoubleFunction<T> — double applyAsDouble(T)
12. Перечислите примитивные специализации интерфейса Function, которые и принимают, и возвращают примитив.
Перечислите примитивные специализации интерфейса Function, которые и принимают, и возвращают примитив.
IntToDoubleFunction, IntToLongFunction
LongToDoubleFunction, LongToIntFunction
DoubleToIntFunction, DoubleToLongFunction
Версий вида IntToIntFunction нет — вместо них используется IntUnaryOperator.
13. Перечислите примитивные специализации функционального интерфейса Supplier.
Перечислите примитивные специализации функционального интерфейса Supplier.
BooleanSupplier — boolean getAsBoolean()
IntSupplier — int getAsInt()
LongSupplier — long getAsLong()
DoubleSupplier — double getAsDouble()
Это единственное семейство, где есть специализация для boolean.
14. Перечислите примитивные специализации функционального интерфейса UnaryOperator.
Перечислите примитивные специализации функционального интерфейса UnaryOperator.
IntUnaryOperator — int applyAsInt(int)
LongUnaryOperator — long applyAsLong(long)
DoubleUnaryOperator — double applyAsDouble(double)
У всех трёх есть default-методы compose() и andThen() и статический identity().
15. Перечислите примитивные специализации функционального интерфейса BinaryOperator.
Перечислите примитивные специализации функционального интерфейса BinaryOperator.
IntBinaryOperator — int applyAsInt(int, int)
LongBinaryOperator — long applyAsLong(long, long)
DoubleBinaryOperator — double applyAsDouble(double, double)
16. Перечислите примитивные специализации функционального интерфейса BiConsumer.
Перечислите примитивные специализации функционального интерфейса BiConsumer.
ObjIntConsumer<T> — void accept(T, int)
ObjLongConsumer<T> — void accept(T, long)
ObjDoubleConsumer<T> — void accept(T, double)
Первый аргумент остаётся объектным, примитивным становится только второй.
17. Перечислите примитивные специализации функционального интерфейса BiFunction.
Перечислите примитивные специализации функционального интерфейса 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?
Перечислите примитивные специализации функционального интерфейса Predicate. Есть ли примитивная версия у BiPredicate?
IntPredicate — boolean test(int)
LongPredicate — boolean test(long)
DoublePredicate — boolean test(double)
У BiPredicate примитивных специализаций нет: интерфейсов вида IntBiPredicate или ObjIntPredicate в пакете не существует.
19. Как по названию интерфейса из java.util.function восстановить его сигнатуру?
Как по названию интерфейса из java.util.function восстановить его сигнатуру?
Имена строятся по шаблону:
Int / Long / Double в начале — тип входного параметра: IntPredicate — boolean test(int).
To + тип — тип возвращаемого значения: ToIntFunction<T> — int applyAsInt(T).
Тип + To + тип — примитивны и вход, и выход: IntToDoubleFunction — double applyAsDouble(int).
Obj + тип — объект плюс примитив: ObjIntConsumer<T> — void accept(T, int).
Bi в начале — два объектных аргумента: BiFunction<T, U, R> — R apply(T, U).
UnaryOperator / BinaryOperator — все типы совпадают: IntBinaryOperator — int applyAsInt(int, int).
Если результат примитивный, к имени метода добавляется суффикс As + тип: applyAsInt, getAsDouble. У test() и accept() суффикса нет — их результат и так фиксирован.
20. Лямбды каких функциональных интерфейсов ожидают методы Stream и IntStream: mapToInt(), map(), mapToObj(), filter(), forEach(), reduce()?
Лямбды каких функциональных интерфейсов ожидают методы 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. Это независимые типы, присвоить переменную одного другому нельзя.