Lambda funkcije u Javi i rad sa kolekcijama
Kratak pregled lambda izraza u Javi i praktična upotreba metoda
map, filter i reduce nad kolekcijama.
- Šta su lambda funkcije i zašto su korisne
- Kako se koriste uz Stream API
- Primeri koda spremni za prezentaciju ili vežbu
Šta su lambda funkcije?
- Lambda funkcije su anonimne funkcije koje omogućavaju funkcionalni stil programiranja u Javi.
- Najčešće se koriste za implementaciju funkcionalnih interfejsa na kraći i čitljiviji način.
- Posebno su korisne uz Stream API i rad sa kolekcijama.
Sintaksa: (parametri) -> izraz
import java.util.function.BinaryOperator;
BinaryOperator<Integer> saberi = (a, b) -> a + b;
System.out.println(saberi.apply(5, 3));
// Ispisuje 8
map — transformacija elemenata
Metoda map transformiše svaki element kolekcije u novi oblik.
Koristi se kada želimo da promenimo vrednosti, a ne da ih filtriramo.
List<String> imena = Arrays.asList("Ana", "Marko", "Jelena");
List<String> velikaImena = imena.stream()
.map(name -> name.toUpperCase())
.collect(Collectors.toList());
System.out.println(velikaImena);
// [ANA, MARKO, JELENA]
filter — filtriranje elemenata
Metoda filter zadržava samo elemente koji ispunjavaju zadati uslov.
Lambda izraz vraća true ili false.
List<Integer> brojevi = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> parniBrojevi = brojevi.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(parniBrojevi);
// [2, 4, 6]
reduce — agregacija elemenata
Metoda reduce kombinuje sve elemente kolekcije u jedan rezultat,
na primer sumu, proizvod ili maksimalnu vrednost.
List<Integer> brojevi = Arrays.asList(1, 2, 3, 4, 5);
int suma = brojevi.stream()
.reduce(0, (a, b) -> a + b);
System.out.println(suma);
// 15
Da li isto može samo uz forEach?
Da — slična funkcionalnost može da se postigne i pomoću forEach,
ali uz više ručnog koda i manje elegancije nego sa Stream API pristupom.
List<String> imena =
Arrays.asList("Ana", "Marko", "Jelena");
List<String> velikaImena =
new ArrayList<>();
imena.forEach(name -> {
velikaImena.add(name.toUpperCase());
});
System.out.println(velikaImena);
// [ANA, MARKO, JELENA]
List<Integer> brojevi =
Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> parniBrojevi =
new ArrayList<>();
brojevi.forEach(n -> {
if (n % 2 == 0) {
parniBrojevi.add(n);
}
});
System.out.println(parniBrojevi);
// [2, 4, 6]
List<Integer> brojevi =
Arrays.asList(1, 2, 3, 4, 5);
int[] suma = {0};
brojevi.forEach(n -> suma[0] += n);
System.out.println(suma[0]);
// 15
Zaključak
forEachmože da imitiramap,filterireduce.- Potrebno je ručno praviti novu listu ili promenljivu za rezultat.
- Stream API je obično čitljiviji i bliži funkcionalnom stilu.
Posebno kod reduce, vidi se da forEach traži pomoćnu promenljivu,
pa je rešenje manje elegantno.
Kratak rezime
| Metoda | Opis | Primer upotrebe |
|---|---|---|
map |
Transformiše elemente | Pretvaranje stringova u velika slova |
filter |
Filtrira elemente po uslovu | Izbor parnih brojeva |
reduce |
Kombinuje elemente u jedan rezultat | Sabiranje svih brojeva u listi |
Lambda izrazi čine kod kraćim, čitljivijim i veoma praktičnim za obradu kolekcija uz Java Stream API.
Pojašnjenje dodatnih pojmova
BinaryOperator<T> je funkcionalni interfejs koji predstavlja operaciju nad dva argumenta istog tipa i vraća rezultat istog tipa. Koristi se za lambda izraze koji kombinuju dva elementa u jedan.
BinaryOperator<Integer> saberi = (a, b) -> a + b;
int rezultat = saberi.apply(5, 3); // rezultat je 8
collect(Collectors.toList()) prikuplja elemente stream-a u novu List kolekciju. Bez poziva ove metode dobijate stream, koji nije kolekcija i ne može se koristiti kao lista (npr. ne možete pozvati get(index)).
List<String> velikaImena = imena.stream()
.map(name -> name.toUpperCase());
// velikaImena je STREAM, ne LISTA — neće raditi kao lista
List<String> velikaImenaLista = imena.stream()
.map(name -> name.toUpperCase())
.collect(Collectors.toList());
// velikaImenaLista je prava lista, može se koristiti kao i svaka druga lista