Core-2: Functional Flashcards
Что такое «лямбда»?
Лямбда-выражение образует реализацию метода, определенного в функциональном интерфейсе:
Основу лямбда-выражения составляет лямбда-оператор, который представляет стрелку ->. Этот оператор разделяет лямбда-выражение на две части: левая часть содержит список параметров выражения, а правая, собственно, представляет тело лямбда-выражения, где выполняются все действия.
interface Operationable { int calculate(int x, int y); } public static void main(String[] args) { Operationable operation = (x, y) -> x + y; int result = operation.calculate(10, 20); Operationable operation2 = (x, y) -> x * y; int result2 = operation2.calculate(10, 20); System.out.println(result); //30 System.out.println(result); //200 }
К каким переменным есть доступ у лямбда-выражений?
Доступ к переменным внешней области действия из лямбда-выражения очень схож к доступу из анонимных объектов. Можно ссылаться на:
- effectively final локальные переменные;
- поля класса, захватывается this значение;
- статические переменные.
К методам по умолчанию реализуемого функционального интерфейса обращаться внутри лямбда-выражения запрещено.
Как отсортировать список строк с помощью лямбда-выражения?
public static List<String> sort(List<String> list){ Collections.sort(list, (a, b) -> a.compareTo(b)); return list; OR: list.sort(String::compareTo); return list; }
Что такое «ссылка на метод»?
method reference: сокращение лямбды, которая содержит лишь один вызов метода.
Иногда лямбда лишь вызывает
существующий в классе метод, который уже реализует нужный функционал, и будет логичнее и нагляднее обратиться к этому методу по имени.
private interface Measurable {
public int length(String string);
}
public static void main(String[] args) {
Measurable a = String::length;
System.out.println(a.length(“abc”));
}
4 типа ссылки на метод
Есть 4 вида:
1) на статический метод любого:
x -> Class.staticMethod(x)
=> Class::staticMethod
2) на метод класса, которому принадлежит обрабатываемый объект:
(obj, args) -> obj.instanceMethod(args)
=> ObjectType::instanceMethod
3) на метод для экземпляра класса:
(obj, args) -> obj.instanceMethod(args)
=> obj::instanceMethod
4) на конструктор:
(args) -> new ClassName(args)
=> ClassName::new
Что выбрать: Lambda VS MethodRef.
Ссылки на методы потенциально более эффективны, чем использование лямбда-выражений. Кроме того, они предоставляют компилятору более качественную информацию о типе и при возможности выбора между использованием ссылки на существующий метод и использованием лямбда-выражения, следует всегда предпочитать использование ссылки на метод.
Объясните выражение System.out::println
Данное выражение иллюстрирует механизм instance method reference: передачи ссылки на метод println() статического поля out класса System.
Что такое «функциональные интерфейсы»?
Функциональный интерфейс - это интерфейс, который определяет только один абстрактный метод.
Чтобы точно определить интерфейс как функциональный, добавлена аннотация @FunctionalInterface, работающая по принципу @Override. Она обозначит замысел и не даст определить второй абстрактный метод в интерфейсе.
Интерфейс может включать сколько угодно default методов и при этом оставаться функциональным, потому что default методы - не абстрактные.
Для чего нужен функциональный интерфейс Function<T,R>
?
Function<T, R> - интерфейс, с помощью которого реализуется функция, получающая на вход экземпляр класса T и возвращающая на выходе экземпляр класса R.
Методы по умолчанию могут использоваться для построения цепочек вызовов (compose, andThen).
Function<String, Integer> toInteger = Integer::valueOf; Function<String, String> backToString = toInteger.andThen(String::valueOf); backToString.apply("123");
Для чего нужны функциональные интерфейсы ` DoubleFunction<R>, IntFunction<R> и LongFunction<R>?`</R></R></R>
-
DoubleFunction<R>
- функция, получающая на вход Double и возвращающая на выходе экземпляр класса R;
-IntFunction<R>
- функция, получающая на вход Integer и возвращающая на выходе экземпляр класса R; -
LongFunction<R>
- функция, получающая на вход Long и возвращающая на выходе экземпляр класса R.
разобрать (compose, andThen) в Function
Для чего нужны функциональные интерфейсы UnaryOperator<T>
, DoubleUnaryOperator, IntUnaryOperator и LongUnaryOperator?
UnaryOperator<T>
(унарный оператор) принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T:
UnaryOperator<Integer> operator = x -> x * x; System.out.println(operator.apply(5)); // 25
- DoubleUnaryOperator - унарный оператор, получающий на вход Double;
- IntUnaryOperator - унарный оператор, получающий на вход Integer;
- LongUnaryOperator - унарный оператор, получающий на вход Long.
Для чего нужны функциональные интерфейсы BinaryOperator<T>, DoubleBinaryOperator, IntBinaryOperator и LongBinaryOperator?</T>
BinaryOperator<T>
(бинарный оператор) - интерфейс, с помощью которого реализуется функция, получающая на вход два экземпляра класса T и возвращающая на выходе экземпляр класса T.
BinaryOperator<Integer> operator = (a, b) -> a + b; System.out.println(operator.apply(1, 2)); // 3
- DoubleBinaryOperator - бинарный оператор, получающий на вход Double;
- IntBinaryOperator - бинарный оператор, получающий на вход Integer;
- LongBinaryOperator - бинарный оператор, получающий на вход Long.
Для чего нужны функциональные интерфейсы Predicate<T>, DoublePredicate, IntPredicate и LongPredicate?</T>
Predicate<T>
(предикат) - интерфейс, с помощью которого реализуется функция, получающая на вход экземпляр класса T и возвращающая на выходе значение типа boolean.
Интерфейс содержит различные методы по умолчанию, позволяющие строить сложные условия (and, or, negate).
Predicate<String> predicate = (s) -> s.length() > 0; predicate.test("foo"); // true predicate.negate().test("foo"); // false
- DoublePredicate - предикат, получающий на вход Double;
- IntPredicate - предикат, получающий на вход Integer;
- LongPredicate - предикат, получающий на вход Long.
Дефолтные Методы Predicate
- default Predicate<T> and(Predicate<? super T> other) - default Predicate<T> negate() { return (t) -> !test(t); } - default Predicate<T> or(Predicate<? super T> other)
Для чего нужны функциональные интерфейсы Consumer<T>, DoubleConsumer, IntConsumer и LongConsumer?
Consumer<T>
(потребитель) - интерфейс, с помощью которого реализуется функция, которая получает на вход экземпляр класса T, производит с ним некоторое действие и ничего не возвращает.
Consumer<String> hello = (name) -> System.out.println("Hello, " + name); hello.accept("world");
имеет дефолтный метод:default Consumer<T> andThen(Consumer<? super T> after)
DoubleConsumer - потребитель, получающий на вход Double;
IntConsumer - потребитель, получающий на вход Integer;
LongConsumer - потребитель, получающий на вход Long.
Для чего нужны функциональные интерфейсы Supplier<T>, BooleanSupplier, DoubleSupplier, IntSupplier и LongSupplier?
Supplier<T>
(поставщик) - интерфейс, с помощью которого реализуется функция, ничего не принимающая на вход, но возвращающая на выход результат класса T;
Supplier<LocalDateTime> now = LocalDateTime::now; now.get();
DoubleSupplier - поставщик, возвращающий Double;
IntSupplier - поставщик, возвращающий Integer;
LongSupplier - поставщик, возвращающий Long.
Для чего нужен функциональный интерфейс BiConsumer<T,U>
?
BiConsumer<T,U>
представляет собой операцию, которая принимает два аргумента классов T и U производит с ними некоторое действие и ничего не возвращает.
Для чего нужен функциональный интерфейс BiFunction<T,U,R>
?
BiFunction<T,U,R>
представляет собой операцию, которая принимает два аргумента классов T и U и возвращающая результат класса R.
Для чего нужен функциональный интерфейс BiPredicate<T,U>
?
BiPredicate<T,U>
представляет собой операцию, которая принимает два аргумента классов T и U и возвращающая результат типа boolean.
Для чего нужны функциональные интерфейсы вида _To_Function
?
DoubleToIntFunction - операция, принимающая аргумент класса Double и возвращающая результат типа Integer;
DoubleToLongFunction - операция, принимающая аргумент класса Double и возвращающая результат типа Long;
IntToDoubleFunction - операция, принимающая аргумент класса Integer и возвращающая результат типа Double;
IntToLongFunction - операция, принимающая аргумент класса Integer и возвращающая результат типа Long;
LongToDoubleFunction - операция, принимающая аргумент класса Long и возвращающая результат типа Double;
LongToIntFunction - операция, принимающая аргумент класса Long и возвращающая результат типа Integer.
Для чего нужны функциональные интерфейсы ToDoubleBiFunction<T,U>, ToIntBiFunction<T,U> и ToLongBiFunction<T,U>
?
ToDoubleBiFunction<T,U>
- операция принимающая два аргумента классов T и U и возвращающая результат типа Double;ToLongBiFunction<T,U>
- операция принимающая два аргумента классов T и U и возвращающая результат типа Long;ToIntBiFunction<T,U>
- операция принимающая два аргумента классов T и U и возвращающая результат типа Integer.
Для чего нужны функциональные интерфейсы ToDoubleFunction<T>, ToIntFunction<T> и ToLongFunction<T>
?
ToDoubleFunction<T>
- операция, принимающая аргумент класса T и возвращающая результат типа Double;ToLongFunction<T>
- операция, принимающая аргумент класса T и возвращающая результат типа Long;ToIntFunction<T>
- операция, принимающая аргумент класса T и возвращающая результат типа Integer.
Для чего нужны функциональные интерфейсы ObjDoubleConsumer<T>, ObjIntConsumer<T> и ObjLongConsumer<T>
?
ObjDoubleConsumer<T>
- операция, которая принимает два аргумента классов T и Double, производит с ними некоторое действие и ничего не возвращает;ObjLongConsumer<T>
- операция, которая принимает два аргумента классов T и Long, производит с ними некоторое действие и ничего не возвращает;ObjIntConsumer<T>
- операция, которая принимает два аргумента классов T и Integer, производит с ними некоторое действие и ничего не возвращает.