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)