Java 8 je už nejaký čas s nami (presnejšie od 18. marca 2014). A je to verzia, ktorá so sebou priniesla hneď niekoľko noviniek (prirovnávajú ju k verzii 5, ktorá priniesla anotácie alebo generika). Niektoré sú naozaj veľké zmeny a nie jeden Java developer krúti hlavou, čo to s tým jazykom Oracle stvára. Ale vývoj nezastavíš a všetko smeruje k Lispu (ako som kdesi čítal 🙂 ). Java 8 je tu a my sa v sérii článkov spolu pozrieme na niektoré novinky, ktoré prináša. Dnes to nebude nič menšie a menej zaujímavé ako Lambda výrazy.
Ak nejaký čas programujete v Jave, museli ste sa stretnúť s niečím, čo sa nazýva anonymná trieda. Je to v podstate implementácia rozhrania pomocou triedy, ktorá nemá meno a je určená na použitie na jednom mieste v kóde. S anonymnými triedami sa stretnete najčastejšie tam, kde je potrebné poslať triedu, ktorá implementuje nejaké rozhranie, a táto jej implementácia má zmysel len na tomto jednom mieste. Napríklad niečo takéto:
button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //tvoj kod pride sem } });
Čo nám ten kód hovorí je, že v rozhraní ActionListener sme pre tento prípad implementovali metódu actionPerfomed. Samotná implementácia metódy je riadok //tvoj kod pride sem. Všetko ostatné je dekorácia okolo toho.
To je celkom dosť kódu kvôli jednému riadku implementácie. Ako programátori, ktorí radi skúšajú nové veci, si to teraz napíšeme Lambda výrazom:
button.addActionListener(() -> { // tvoj kod pride sem });
To je, ako musíte uznať, o dosť menej ozdôb okolo samotného tela metódy. Čo teda Lambda výrazy sú?
Laicky by sa dalo povedať, že reprezentujú odkaz na metódu, ktorá bola definovaná na danom mieste. Je to teda anonymná metóda – nemá názov – a aj preto sa dá použiť len tak, kde bola definovaná. Poďme si teraz trochu rozpitvať syntax. Správny Lamba výraz sa skladá z troch zložiek:
Zoznam argumentov môže byť prázdny, ako napríklad:
() -> { System.out.println(„Gordon Freeman“); }
Typy argumentov môžu a nemusia byť definované. Tieto dva výrazy sú rovnocenné:
(e) -> { System.out.println(e); } (String e) -> { System.out.println(e); }
V prípade, ak typ nie je explicitne zadefinovaný, je odvodený. Ak má Lambda výraz len jeden parameter, môžete úplne vynechať zátvorky pre parametre:
e -> { System.out.println(e); }
Čo sa týka tela Lambda výrazu, tiež o ňom platí niekoľko vecí. Ak obsahuje len jeden riadok, nemusíme používať zložené zátvorky:
e -> System.out.println(e);
A ak má Lambda výraz vracať hodnotu (typ hodnoty je opäť odvodený) a telo obsahuje jeden riadok, tak kľúčové slovo return môžete vynechať:
(x, y) -> x + y
Lambda výrazy majú jednu špecialitu. Vedia pristupovať k lokálnym premenným definovaným v scope ako sú oni samé, ale daná premenná musí byť final. Musí to napríklad vyzerať nejako takto:
int x = 10; doSomething(e -> System.out.println(x));
V tomto prípade sa teda Lambda odkazuje na premennú x, ktorá je definovaná na tej istej úrovni ako samotná lambda. Možno ste si všimli, že som nepoužil kľúčové slovo final. V tomto prípade ani nie je treba. S 8-kou totiž prišiel aj nový pojem effective final. To je vtedy, keď premenná síce nie je označená ako final, ale hodnota je jej priradená len raz. Lambde stačí aj effective final.
Lambda výrazy predstavujú naozaj veľa syntaktického cukru a na prvý pohľad by mohli vyzerať len ako hračka pre programátora. Ale v skutočnosti je to jeden prvok, čo robí v Jave 8 z funkcií takzvaný first-class citizen. To znamená, že vedľa tried, objektov a primitívnych typov pribudol nový druh, s ktorým je možné manipulovať tak, že sa uchováva v premennej alebo posiela ako parameter do metódy. Toto je pre Javu veľký filozofický posun a otvára to dvere pre ďalšie možnosti.
A aj Lambda výrazy sú v skutočnosti len jedným dielom skladačky a keď sa začnú kombinovať s novými funkčnými rozhraniami v balíku java.util.function a novým Collection API, len vtedy to začne byť zaujímavé. Ale o tom nabudúce.