V tomto a v následujících článcích se podíváme na zoubek lambda výrazem. Budeme si je vysvětlovat zcela dopodrobna, abychom je pochopili a využívali.
Obsahově se zaměříme na tyto oblasti:
- porozumění lambda výrazům,
- použití lambda výrazů,
- funkcionální rozhraní (functional intefaces),
- reference metod (method references),
- vylepšení na kolekcích.
Proč použít lambda výrazy? Řekneme si pár odrážek, proč je používat.
- povoluje použít takzvané funkcionální programování, což je dosud něco, řekl bych divné, protože Java je objektově orientovaný jazyk,
- zpřehledňují kód, lepší čitelnost v některých případech, kde bychom použili několik zbytečných řádků, abychom napsali totéž.
Možná se zamýšlíš, proč používat funkcionální programování v jazyce, který je objektově orientovaný. Už není OOP tak dobré? Už zanikne? Ne, nezanikne a java je a myslím si, že pořád bude objektově orientovaný jazyk. Toto funkcionální programování ber jen jako další nástroj, který jako vývojář máš ve své ruce.
U OOP jsou vývojáři zvyklí přemýšlet v podstatných jménech, v objektech, ve třídách.
Například Pes štěká. Štěkání je součástí Psa. Tím pádem metoda, která bude zajišťovat psí štěkání, je součástí třídy Pes.
Někdy ale potřebuji kus kódu, metodu – nebo jinak řečeno funkci, která nepatří do žádné třídy speciální.
Podsunutí chování do metody
Uvažuj nad tím, že máš metodu, která na konzoli vypíše nějaký text. Například staré známé Hello World. Pro tento účel bychom si vytvořili třídu, které by byla metoda pro vypsání Hello Word. Tuto metodu bychom pak vypsali na konzoli v main metodě. Příklad v idea Lambda2.
Naším úkolem bude nyní předělat tento kód tak, abych dané metodě podsunul chování a uvnitř té metody se jen provede to chování. Ukažme si na příkladu.
Takže jsme udělali, co jsme chtěli. Do metody jsme podsunuli chování jako argument a poté jsme jej provedli. Ale ne tak přesně. Do metody jsme podsunuli něco, co má v sobě chování. Podsunuli jsme implementaci rozhraní, která má v sobě metodu, která provede očekávané chování.
Právě tomuto chtějí lambda výrazy zabránit. Chtějí zabránit tomu, abychom podsouvali objekty, ale chtějí, abychom podsouvali funkce.
Namísto tohoto:
public void printHelloWord(IHelloWord helloWord){
helloWord.sayHello();
}
chceme do metody vložit nějakou akci, nějakou funkci. Tento přístup umožňuje chovat se k funkcím jako k hodnotám.
public void printHelloWord(funkcia){
funkcia();
}
Pokud napíšu String jméno = “Jaro”; tak jsem hodnotu Jaro přidělil do proměnné jméno. Nyní jsme ale nastínili, že do nějaké proměnné bychom chtěli vložit blok kódu, který prezentuje naši funkci. Takže blok kód by se stal hodnotou a ta by se dala vložit do proměnné. Takže tam, kde používám danou proměnnou, tak tam používám i danou funkci, která je v ní.
Pro představivost, chceme dosáhnout tohoto:
premennaSFunkciou = public void sayHello() {
System.out.println("HelloWord impls");
}
Toto je možné pomocí lambda výrazů. Nejprve se ale podívejme na tento kus kódu a řekněme si, co nepotřebujeme:
- public – označuje mi, jestli je něco veřejně dostupné mimo třídu, dává smysl v kontextu třídy, tady ale přidělujeme do proměnné, tak to nepotřebujeme, neboť funkce je dostupná tomu, kdo pracuje s danou proměnnou.
premennaSFunkciou = void sayHello() {
System.out.println("HelloWord impls");
}
- název sayHello = pokud přistupujeme k hodnotě, která je v proměnné, tak k ní přistupujme názvem proměnné, v našem případě je název proměnné proměnnou SFunkcí, takže ani druhé jméno nepotřebujeme.
premennaSFunkciou = void () {
System.out.println("HelloWord impls");
}
- typ návratové hodnoty – při psaní lambda výrazů nemusím psát, jaký je návratový typ, překladač ví, podle nitra metody, co se vrací.
premennaSFunkciou = () {
System.out.println("HelloWord impls");
}
Toto ale ještě není lambda výraz. Pokud napíšu šipku (pomlčka - a znaménko větší >) mezi závorky a blok kódu, tak tehdy jsme vytvořili labmda výraz.
premennaSFunkciou = () -> {
System.out.println("HelloWord impls");
}
Pokud metoda obsahuje jen jeden řádek, tedy ne více řádků, tak lze dále upravit tento výraz a to tak, že odstraníme složené závorky. Pokud je více řádků, tak složené závorky ponecháme.
premennaSFunkciou = () -> System.out.println("HelloWord impls");
Teď si už umíme představit, udělat, to, že pošleme funkci jako parametr metody a uvnitř spustíme danou funkci.
public void printHelloWord(------){
-----();
}
Do metody můžeme vložit jako argument při volání metody přímo lambda výraz.
printHelloWord(() -> System.out.println("HelloWord impls")){
Příklady
Napiš metodu, která vezme jako parametr číslo a vynásobí ho 5ti.
nasobokPiatichFunkcia = public int nasobokPiatich(int i){
return i*5;
}
Přepíšeme to na lambda výraz, vyškrtám všechno, co nepotřebuji. Tedy název, návratovou hodnotu a modifikátor přístupu.
nasobokPiatichFunkcia = (int i){
return i*5;
}
Napíšeme tam šipku a jelikož řádek je tam jen jeden, tak umíme odmazat kudrnaté závorky.
nasobokPiatichFunkcia = (int i) -> return i*5;
Tady máme další pomůcku, nebo možnost škrtat. Jelikož java kompilátor zná vnitřek metody a ví, co má vrátit, můžu vymazat i return.
nasobokPiatichFunkcia = (int i) -> i*5;
Když máme jednořádkový lambda výraz bez složených závorek, tak je nezbytné nepoužívat return.
Sčítání
scitaniFunkce = (int a, int b) -> a+b;
Odčítání
odcitaniFunkce = (int a, int b) -> a-b;
Bezpečné dělení
bezpecneDelenieFunkcia = (int a, int b) -> {
if(b==0) {
return 0 ;
}
return a/b;
};
Spojení řetězců
stringJoin = (String x, String y) -> x.concat(y);
Stále jsme v Javě. Tedy v typovém jazyce. Jaké jsou typy těchto proměnných, které v sobě drží lambda výrazy?
Video:
Pokud tě více baví poslouchat a dívat, tak si můžeš prohlédnout sérii videí o lambda výrazech v kurzu Java pro pokročilé.
Záver
Pokud by ses chtěl dozvědět o Javě víc nebo jsi nepochopil všechno, tak jsem i pro tebe připravil online
kurzy o Javě na https://skillmea.sk.
Zakomponuji i malou reklamu. Ve spolupráci s tvůrci židle
Neseda.com ti nabízím s kódem/kuponem JaroslavBeno 10% slevu (aplikovatelná i na zlevněnou židli).
Já jsem Jaro a my se vidíme, slyšíme-li Bůh dá příště.
Čaves.