Ce face Expresii lambda
O expresie lambda scrie o bucată de comportament ca pe o valoare: n -> n % 2 == 0 este „funcția care spune dacă un număr e par”. O poți pune într-o variabilă, o poți trimite unei metode (lista.removeIf(...), lista.sort(...)) sau o poți returna.
Tipul unei lambda este o interfață funcțională: o interfață cu exact o metodă abstractă. Pachetul java.util.function are cele mai folosite: Function<T, R> (primește T, dă R), Predicate<T> (dă boolean), Consumer<T> (nu dă nimic), Supplier<T> (nu primește nimic), BiFunction, UnaryOperator. Și interfețele vechi precum Runnable și Comparator sunt funcționale.
Forme: cu un singur parametru, parantezele pot lipsi; tipurile parametrilor se deduc; dacă corpul e o singură expresie, nu ai nevoie de acolade și de return. O lambda poate folosi variabile locale din jur doar dacă sunt efectiv finale (nu se modifică).
Exemple
Exemplul 1: Lambda în metodele colecțiilor
removeIf primește un Predicate, replaceAll un UnaryOperator, sort un Comparator și forEach un Consumer.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> orase = new ArrayList<>(List.of("iași", "cluj-napoca", "arad", "timișoara", "deva"));
orase.removeIf(o -> o.length() <= 4);
System.out.println("fără nume scurte: " + orase);
orase.replaceAll(o -> o.substring(0, 1).toUpperCase() + o.substring(1));
orase.sort((a, b) -> b.compareTo(a));
orase.forEach(o -> System.out.println("- " + o));
}
}
Rezultat
fără nume scurte: [cluj-napoca, timișoara]
- Timișoara
- Cluj-napoca
Exemplul 2: Interfețele din java.util.function
Fiecare variabilă are tipul unei interfețe funcționale și se apelează prin metoda ei: apply, test, accept, get. andThen și negate combină funcții.
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
Function<Double, Double> cuTva = pret -> pret * 1.21;
Function<Double, Long> rotunjit = x -> Math.round(x);
Predicate<Integer> promovat = nota -> nota >= 5;
Consumer<String> salut = nume -> System.out.println("Bună, " + nume + "!");
Supplier<String> oras = () -> "Iași";
BiFunction<Integer, Integer, Integer> arie = (l, h) -> l * h;
System.out.println("100 lei cu TVA: " + cuTva.apply(100.0));
System.out.println("rotunjit: " + cuTva.andThen(rotunjit).apply(99.9));
System.out.println("4 promovat? " + promovat.test(4) + ", corigent? " + promovat.negate().test(4));
salut.accept("Mihaela");
System.out.println("oraș implicit: " + oras.get());
System.out.println("arie 5x8: " + arie.apply(5, 8));
}
}
Rezultat
100 lei cu TVA: 121.0
rotunjit: 121
4 promovat? false, corigent? true
Bună, Mihaela!
oraș implicit: Iași
arie 5x8: 40
Exemplul 3: Lambda cu bloc și variabile capturate
Lambda cu acolade are nevoie de return. Variabila prag este capturată din metodă; pentru că nu se mai schimbă, este efectiv finală. O metodă poate returna o lambda, ca o „fabrică” de funcții.
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
public class Main {
static Function<Double, Double> reducere(int procent) {
return pret -> pret * (100 - procent) / 100;
}
public static void main(String[] args) {
double prag = 50;
Predicate<Double> scump = pret -> pret > prag;
Function<String, String> eticheta = (String text) -> {
String curat = text.strip();
if (curat.isEmpty()) {
return "(fără nume)";
}
return curat.toUpperCase();
};
for (double p : List.of(19.9, 75.0, 120.0)) {
System.out.println(p + " scump? " + scump.test(p) + ", cu -20%: " + reducere(20).apply(p));
}
System.out.println(eticheta.apply(" brânză de burduf "));
System.out.println(eticheta.apply(" "));
}
}
Rezultat
19.9 scump? false, cu -20%: 15.92
75.0 scump? true, cu -20%: 60.0
120.0 scump? true, cu -20%: 96.0
BRÂNZĂ DE BURDUF
(fără nume)
Greșeli frecvente
- Modifici o variabilă locală folosită în lambda (
total += xînforEach):local variables referenced from a lambda expression must be final or effectively final. Folosește un stream cusum()sau o buclă obișnuită. - Uiți
returnîntr-o lambda cu acolade care trebuie să returneze ceva:missing return statement, saubad return type in lambda expression. - Pui o lambda într-o variabilă
varsauObject:lambda expression not expected here. Lambda are nevoie de un tip țintă care este o interfață funcțională.
Comenzi înrudite
Referințe la metode (::): O referință la metodă (Clasa::metoda) este o lambda prescurtată care doar apelează o metodă existentă.Interfețe (interface, implements): O interfață (interface) descrie ce metode trebuie să aibă o clasă; clasa o promite cu implements și poate implementa mai multe interfețe.Stream-uri (ideea): Un stream descrie o prelucrare de date ca un lanț: sursă, operații intermediare (filter, map, sorted) și o operație finală (toList, count, collect).Comparatori (Comparable și Comparator): Comparable dă ordinea naturală a unei clase (compareTo); Comparator descrie orice altă ordine și se combină cu comparing, thenComparing și reversed.Function: O funcție care primește o valoare de tip T și returnează una de tip R; o apelezi cu apply.Predicate: O condiție: primește o valoare și răspunde true sau false prin metoda test; folosită de filter, removeIf, anyMatch.