Что такое «лямбда»?
Лямбда-выражение образует реализацию метода, определенного в функциональном интерфейсе:
Основу лямбда-выражения составляет лямбда-оператор, который представляет стрелку ->. Этот оператор разделяет лямбда-выражение на две части: левая часть содержит список параметров выражения, а правая, собственно, представляет тело лямбда-выражения, где выполняются все действия.
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
}К каким переменным есть доступ у лямбда-выражений?
Доступ к переменным внешней области действия из лямбда-выражения очень схож к доступу из анонимных объектов. Можно ссылаться на:
Как отсортировать список строк с помощью лямбда-выражения?
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
Для чего нужны функциональные интерфейсы 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
Для чего нужны функциональные интерфейсы 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Дефолтные Методы 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, производит с ними некоторое действие и ничего не возвращает.