Sunteți pe pagina 1din 25

1

Prezentare 15:
Lambda expresii
Verificare de tip,
Inferenta de tip,
Restrictii
PROGRAMARE ORIENTATA
OBIECT
2020
Lambda expresii – verificare de tip

 O lambda expresie este o instanta a unei interfete functionale, dar


nu contine informatie referitor la interfata implementata
 Tipul lambda expresiei - tip destinatie - este inferat din contextul de
utilizare

List<Mar> maiGreuDecat150g =
filter(inventar, (Mar mar) -> mar.getGreutate() > 150);

11.01.2021 POO 2
Lambda expresii – verificare de tip
filter(inventar, (Mar mar) -> mar.getGreutate() > 150);
Care este contextul de
utilizare a lambda expresiei?
filter(List<Mar> inventar, Predicate<Mar> p);
Tipul destinatie este
Predicate<Mar>
Tip destinatie Mar -> Boolean se
potriveste cu signatura
Care este metoda lambda expresiei
abstracta in iterfata
Predicate<Mar> boolean test(Mar mar)

Mar -> boolean

11.01.2021 POO 3
Aceeasi lambda, diferite interfete

 Prin tipul destinatie, o lambda expresie poate fi asociata cu


interfete functionale diferite daca au o signatura compatibila a
metodei abstracte
Comparator<Mar> c1 =
(Mar m1, Mar m2) -> m1.getGreut().compareTo(m2.getGreut());
ToIntBiFunction<Mar, Mar> c2 =
(Mar m1, Mar m2) -> m1.getGreut().compareTo(m2.getGreut());
BiFunction<Mar, Mar, Integer> c3 =
(Mar m1, Mar m2) -> m1.getGreut().compareTo(m2.getGreut());

11.01.2021 POO 4
Inferenta de tip

 Compilatorul poate infera signatura unei lambda expresii din tipul


destinatie

Fara inferenta de tip

Comparator<Mar> c =
(Mar m1, Mar m2) -> m1.getGreutate().compareTo(m2.getGreutate());

Cu inferenta de tip

Comparator<Mar> c =
(m1, m2) -> m1.getGreutate().compareTo(m2.getGreutate());

11.01.2021 POO 5
Utilizarea variabilelor locale in lambda
expresii

 Lambda expresiile pot utiliza variabile libere (nu sunt parametri si


sunt definite in afara lambda), similar claselor anonime
int nrPort = 1666;
Runnable r = () -> System.out.println(nrPort);
 Restrictii:
 pot referi variabile de clasa si statice fara restrictii

 variabilele locale trebuie sa fie final

int nrPort = 1666;


Runnable r = () -> System.out.println(nrPort); var. locala nrPort nu
este final
nrPort = 34599;

11.01.2021 POO 6
Referinte la metode

 Permit reutilizarea definitiilor metodelor si transmiterea lor ca


lambda expresii
Inainte:

inventar.sort((Mar m1, Mar m2) ->


m1.getGreutate().compareTo(m2.getGreutate()));

Dupa: utilizarea referintei si java.util.Comparator.comparing

inventar.sort(comparing(Mar::getGreutate));

11.01.2021 POO 7
Referinte la metode

 Pot fi vazute ca o scurtatura pentru lambda care apeleaza doar o


anumita metoda
este referinta la metoda getGreutate
Mar::getGreutate definita in clasa Mar

este o scurtatura pentru lambda:

(Mar mar) -> mar.getGreutate()

11.01.2021 POO 8
Referinte la metode

 Exista trei tipuri de referinte la metode:


 referinta unei metode statice: Integer::parseInt

 referinta unei metode definite in clasa: String::length

(String s) -> s.toUpperCase() => String::toUpperCase()


 referinta unei metode definite in clasa, accesata prin intermediul

unui obiect sau expresii: varTanz::getVal,


unde varTranz este o variabila de tip Tranzactie si getVal este
o metoda definita in Tranzactie
() -> expTranz.getVal() => expTranz::getVal

11.01.2021 POO 9
Referinte la metode

 referinta unei metode definite in clasa, accesata prin intermediul


unui obiect sau expresii
private boolean eNumeValid(String str) {
return Character.isUpperCase(str.charAt(0));
}

filter(cuvinte, this::eNumeValid)

11.01.2021 POO 10
Referinte la metode

Lambda (args) -> NumeClasa.metStatica(args)

Referinta metoda NumeClasa::metStatica

Lambda (arg0, rest) -> arg0.metClasa(rest)


arg0 este e tip
Referinta metoda NumeClasa::metClasa NumeClasa

Lambda (args) -> expr.metClasa(args)

Referinta metoda expr::metClasa

11.01.2021 POO 11
Referinte la metode

 Exemplu: sortarea unei liste de siruri, ignorand diferenta dintre litere


mari/mici
List<String> str = Arrays.asList(“a”,”b”,”A”,”B”);
str.sort((s1, s2) -> s1.compareToIgnoreCase(s2));

 Utilizand referinte la metode:

List<String> str = Arrays.asList(“a”,”b”,”A”,”B”);


str.sort(String::compareToIgnoreCase);

11.01.2021 POO 12
Referinte la metode

ToIntFunction<String>strToInt = (String s) -> Integer.parseInt(s);


ToIntFunction<String>strToInt = Integer::parseInt;

BiPredicate<List<String>, String> contine = (list, elem) -> list.contains(elem);


BiPredicate<List<String>, String> contine = List::contains;

Predicate<String> startCuNr = (String str) -> this.startCuNr(str);


Predicate<String> startCuNr = this::startCuNr(str);

11.01.2021 POO 13
Referinte la constructori

 NumeClasa::new
 Similar cu referinta la o metoda statica
referinta la constructorul
Supplier<Mar> c1 = Mar::new; implicit Mar()
Mar m1 = c1.get();
apelul metodei get din
Supplier creeaza un nou mar

 Echivalent cu: lambda pentru a crea un Mar


utilizand constructorul
Supplier<Mar> c1 = () -> new Mar(); implicit Mar()
Mar m1 = c1.get();
apelul metodei get din
Supplier creeaza un nou mar
11.01.2021 POO 14
Referinte la constructori

 Un constructor cu signatura Mar(Integer greut), se potriveste cu


interfata Function
referinta la constructorul
Function<Integer, Mar> c2 = Mar::new; Mar(Integer greut)
Mar a2 = c2.apply(150);
metoda apply (greutate) din
Function creeaza un obiect Mar

 Echivalent cu:

Function<Integer, Mar> c2 = (greut) -> new Mar(greut);


Mar m2 = c2.apply(150);

11.01.2021 POO 15
Referinte la constructori

 Pentru un constructor cu doua argumente Mar(Culoare cul, Integer


greut), poate fi folosita interfata BiFunction:
referinta la constructorul
BiFunction<Culoare, Integer, Mar> c3 = Mar::new; Mar(Culoare c, Integer g)
Mar m3 = c2.apply(VERDE, 150);
metoda apply (culoare,
greutate) din BiFunction
creeaza un obiect de tip Mar

 Echivalent cu:
BiFunction<String, Integer, Mar> c3 = (culoare, greut) -> new Mar(culoare,
greut);
Mar m3 = c3.apply(VERDE, 150);

11.01.2021 POO 16
Utilizare lambda si referinte la metode

 Exemplu: sortarea unei liste de mere folosind diferite strategii


 Solutia 1: parametrizarea comportamentului

void sort(Comparator<? super E> c)

public class ComparatorMar implements Comparator<Mar> {


public int compare(Mar m1, Mar m2) {
return m1.getGreutate().compareTo(m2.getGreutate());
}
}

inventar.sort(new ComparatorMar());

11.01.2021 POO 17
Utilizare lambda si referinte la metode

 Solutia 2: utilizarea unei clase anonime

inventar.sort(new Comparator<Mar>() {
public int compare(Mar m1, Mar m2) {
return m1.getGreutate().compareTo(m2.getGreutate());
}
});

11.01.2021 POO 18
Utilizare lambda si referinte la metode

 Solutia 3: utilizarea lambda expresiilor

Signatura metodei abstracte din Comparator este (T, T) -> int

inventar.sort((Mar m1, Mar m2) ->


m1.getGreutate().compareTo(m2.getGreutate());
);

Folosind capacitatea compilatorului de a infera tipul parametrilor unei


lambda expresii:

inventar.sort((m1, m2) -> m1.getGreutate().compareTo(m2.getGreutate()));

11.01.2021 POO 19
Utilizare lambda si referinte la metode

 Solutia 3: utilizarea lambda expresiilor

Poate fi facuta solutia mai expresiva?


Comparator are o metoda statica comparing care primeste un parametru
Function care extrage o cheie Comparable si creeaza un obiect Comparator

Comparator<Mar> c = Comparator.comparing((Mar m) ->


m.getGreutate());

import static java.util.Comparator.comparing;


inventar.sort(comparing(mar -> mar.getGreutate()));

11.01.2021 POO 20
Utilizare lambda si referinte la metode

 Solutia 4: utilizarea referintelor la metode

import static java.util.Comparator.comparing;


inventar.sort(comparing(Mar :: getGreutate());

11.01.2021 POO 21
Compunerea lambda expresiilor

 Compunerea comparatorilor
Metoda statica Comparator.comparing intoarce un comparator
pe baza unei functii (Function) care extrage cheia pentru
comparatie:
Comparator<Mar> c = Comparator.comparing(Mar :: getGreutate();

 Daca vrem sa sortam merele in ordinea descrescatoare a


greutatii, interfata contine o metoda default reversed care
inverseaza ordinea comparatorului:
inventar.sort(comparing(Mar :: getGreutate().reversed());

11.01.2021 POO 22
Compunerea lambda expresiilor

 Compunerea comparatorilor

 Inlantuirea comparatorilor
Daca avem doua mere cu aceeasi greutate, vrem sa le sortam
dupa tara de origine
inventar.sort(comparing(Mar :: getGreut()
.reversed()
.thenComparing(Mar :: getTara));

11.01.2021 POO 23
Compunerea lambda expresiilor

 Compunerea predicatelor

 Interfata Predicate contine trei metode care permit


compunerea predicatelor: negate, and, or
Predicate<Mar>marDifRosu = marRosu.negate();
Predicate<Mar>marRosuGreu =
marRosu.and(mar -> mar.getGreutate() > 150);

Predicate<Mar>marRosuGreuSauVerde =
marRosu.and(mar -> mar.getGreutate() > 150)
.or(mar -> VERDE.equals(m.getCuloare()));

11.01.2021 POO 24
Compunerea lambda expresiilor

 Compunerea functiilor

 interfata Function contine metodele andThen si Compose care


intorc instante de tip Function
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2; matematic: g(f(x))
Function<Integer, Integer> h = f.andThen(g);
int rez = h.apply(1); intoarce 4

Function<Integer, Integer> f = x -> x + 1;


Function<Integer, Integer> g = x -> x * 2;
matematic: f(g(x))
Function<Integer, Integer> h = f.compose(g);
int rez = h.apply(1); intoarce 3
11.01.2021 POO 25

S-ar putea să vă placă și