Ce face Referințe la metode (::)
Când o lambda nu face altceva decât să apeleze o metodă, o poți scrie mai scurt cu ::. lista.forEach(x -> System.out.println(x)) devine lista.forEach(System.out::println). Ca și lambda, referința are nevoie de o interfață funcțională ca tip țintă.
Există patru feluri: metodă statică (Integer::parseInt), metoda unui obiect anume (System.out::println, cos::adauga), metodă de instanță apelată pe primul parametru (String::length înseamnă s -> s.length()) și constructor (Elev::new, ArrayList::new, int[]::new).
Referințele sunt des folosite cu stream-uri și comparatori: map(String::strip), Comparator.comparing(Elev::nume). Dacă lambda face mai mult decât un singur apel, păstreaz-o ca lambda.
Exemple
Exemplul 1: Cele patru feluri de referințe
Fiecare referință înlocuiește lambda din comentariu. Elev::new alege constructorul cu un parametru String, potrivit cu Function<String, Elev>.
import java.util.List;
import java.util.function.Function;
record Elev(String nume) { }
public class Main {
public static void main(String[] args) {
List<String> texte = List.of("12", "7", "30");
// 1. metodă statică: s -> Integer.parseInt(s)
List<Integer> numere = texte.stream().map(Integer::parseInt).toList();
System.out.println("numere: " + numere);
// 2. metoda unui obiect anume: x -> System.out.println(x)
numere.forEach(System.out::println);
// 3. metodă de instanță pe parametru: s -> s.toUpperCase()
List<String> orase = List.of("iași", "bacău").stream().map(String::toUpperCase).toList();
System.out.println(orase);
// 4. constructor: nume -> new Elev(nume)
Function<String, Elev> creeaza = Elev::new;
System.out.println(creeaza.apply("Teodora"));
}
}
Rezultat
numere: [12, 7, 30]
12
7
30
[IAȘI, BACĂU]
Elev[nume=Teodora]
Exemplul 2: Referințe în stream-uri și comparatori
Comparator.comparing(Produs::pret) sortează după preț, map(Produs::nume) extrage numele, iar String[]::new creează array-ul de mărimea potrivită.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
record Produs(String nume, double pret) {
boolean laReducere() {
return pret < 10;
}
}
public class Main {
public static void main(String[] args) {
List<Produs> raft = List.of(
new Produs("cafea", 39.9), new Produs("apă", 3.5),
new Produs("ciocolată", 8.75), new Produs("ceai", 14.0));
List<Produs> ieftine = raft.stream().filter(Produs::laReducere).toList();
System.out.println("la reducere: " + ieftine);
String[] nume = raft.stream()
.sorted(Comparator.comparing(Produs::pret))
.map(Produs::nume)
.toArray(String[]::new);
System.out.println("după preț: " + Arrays.toString(nume));
}
}
Rezultat
la reducere: [Produs[nume=apă, pret=3.5], Produs[nume=ciocolată, pret=8.75]]
după preț: [apă, ciocolată, ceai, cafea]
Greșeli frecvente
- Pui paranteze:
System.out::println()nu compilează. Referința numește metoda, nu o apelează. - Folosești o referință ambiguă, de exemplu
Integer::toStringcuFunction<Integer, String>: există și metoda staticătoString(int), și cea de instanță, iar compilatorul spuneincompatible types: invalid method reference. Scrie lambda explicit. - Forțezi o referință acolo unde lambda face mai multe lucruri.
x -> x.strip().toLowerCase()nu are o referință echivalentă; lasă lambda.
Comenzi înrudite
Expresii lambda: O lambda este o funcție scurtă, fără nume, scrisă ca parametri -> corp, folosită oriunde se așteaptă o interfață funcțională.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.Constructori: Constructorul are numele clasei, nu are tip returnat și pregătește obiectul nou; o clasă poate avea mai mulți constructori.