Lambdas

Что под капотом

Functional interface — only one abstract method (has functional descriptor)
4 основных — Supplier, Consumer, Predicate, Function

Типы lambda

Consumer<T>: Consumer<String> sampleConsumer = System.out::println;
Predicate<T>: Predicate<String> samplePredicate = (String s) -> s.isEmpty();
BiPredicate<T, U>: BiPredicate<String,String> sampleBiPredicate = (String s1, String s2) -> s1.equals(s2);
Supplier<T>: Supplier<Apple> apConstructor = Apple::new;
Function<T, R>: Function<Apple, Int> getWeight = Apple::getWeight;
BiFunction<T,U,R>: BiFunction<Int, Color, Apple> constructorWith2Args = Apple::new;
UnaryOperator<T>: UnaryOperator<Apple> newGreenApple = (apple) -> new Apple(apple.getWeight(), Color.GREEN);
BinaryOperator<T>: BinaryOperator<Apple> newGreenApple = (apple, weight) -> new Apple(weight.getWeight(), apple.getColor());
BiConsumer<T, U>:

Для трех примитивных типов — int, long, double — отдельные типы

Method references

  1. Static methods of class —
(arg0) -> ClassName::static
  1. Instance metthod of class —
(str) - >  str.length() => String::length
  1. method of variable — str::toUpperCase()
  2. constructor reference =
Supplier<Apple> aps = Apple::new;

MethodReferenceChain.getStream()::ordered() — > store reference to Stream and used it again. Repeat call ends with error.

Composing Lambdas

For Function type =

andThen, compose

For Predicate =

negate, or, and

For Comparator =

reversed, thenComparing(Int, Long, Double)

Testing

1) Testing if lambda in field
2) Testing lambda behavior
3) Extract lambda code in method and use method reference
4) High-order — change lambda in parameters and test it

Patterns

1) Strategy — functional interface, instance — lambdas
2) Template method — add parameter for lambda
3) Observer — if implementation of Observer is simple without fields -> can change with lambdas
4) Chain of responsibility — composite lambdas
5) Factory — ? map of name of product with function/method reference for constructor

Capture variables

instance variables and static variables — without restriction (instance variables — like capturing final variable this)
Local variables == final or effectively final (assigned only ones).
Instance variables are stored on the heap, whereas local variables live on the stack.
Java implements access to a free local variable as access to a copy of it, rather than access to the original variable.