Java Lambda výrazy: Čo sú a ako ich používať?

Mnohí Java programátori, sa s lambda výrazmi už stretli. Táto funkcionalita bola pridaná už vo verzii Java 8 z roku 2014, takže v súčasnosti už nejde o žiadnu novinku. Je často využívaná programátormi a má množstvo výhod. Ak ti však  lambda výrazy robia problémy alebo nevieš, čo predstavujú, si na správnom mieste.

Čo je lambda výraz (expression)?

Lambda výraz predstavuje funkcionalitu, ktorá bola pridaná ešte v Jave 8. Ide o krátky blok kódu podobný metóde, ale na rozdiel od nej nepotrebuje jej názov metódy a môže byť implementovaný rovno v tele metódy.

Lambda má niekoľko výhod, a to napríklad, že:

  • sprehľadňuje kód a poskytuje lepšiu čitateľnosť – namiesto niekoľkoriadkového kódu stačí napísať len zopár riadkov,
  • povoľuje použiť funkcionálne programovanie – znamená to použiť funkciu ako vstupný parameter inej funkcie,
  • zlepšuje proces paralelizovania kódu – inak povedané, efektívnejšie vykonávanie kódu na viacjadrových procesoch.

Syntax lambda výrazu

Každý lambda výraz musí mať správnu syntax. Len v takom prípade bude mať želaný efekt. Lambda musí obsahovať:

  • zoznam argumentov,
  • znak šípky,
  • telo výrazu.

V praxi to môže vyzerať takto:

(zoznam argumentov) -> telo výrazu

(zoznam argumentov) -> {výraz1; výraz2, …}

 Zoznam argumentov môže byť aj prázdny, napríklad:

() -> { System.out.println(„Ahoj“); }

 Telo výrazu musí obsahovať zložené zátvorky iba v prípade, ak obsahuje viac ako jeden riadok kódu. V spomenutom príklade ho môžeme vynechať:

() -> System.out.println(„Ahoj“);

 Typy argumentov môžu a nemusia byť definované, čo znamená, že tieto dva výrazy sú ekvivalentné:

(x) -> System.out.println(x);

(Int x) -> System.out.println(x);

 Lambda vie tiež navracať hodnoty, a to bez použitia slova return. Kompilátor si ho vie sám odvodiť:

(x, y) -> x + y

Vedel si, že...

… Ak má lambda len jeden parameter, zátvorky nie sú povinné? Kód má teda podobu: x -> System.out.println(x);.

Príklady použitia lambda

Pre lepšiu predstavu prinášame tri príklady, ako sa dá lambda výraz použiť.

Príklad č. 1: Lambda výraz vo forEach

Lambda výrazy sa často používajú ako parameter funkcie.

package com.test;

import java.util.ArrayList;

public class LambdaExample1 {

	public static void main(String[] args) {
		ArrayList<Integer> numbers = new ArrayList<Integer>();
		numbers.add(1);
		numbers.add(2);
		numbers.add(3);
		// Vytlaci na konzolu 1 2 3 pod sebou. 
		numbers.forEach(x -> System.out.println(x));
	}
}

Lambda výraz sa dá uložiť do premennej. Platí tu však, že iba vtedy, keď je premenná interface s jednou metódou. V takýchto prípadoch musí mať lambda výraz rovnaký počet parametrov a návratový typ ako daná metóda.

Java má mnoho používateľských rozhraní. Jedným je napríklad interface Consumer, ktorý využívajú zoznamy:

java.util.function.Consumer<Integer> function = x -> System.out.println(x);
numbers.forEach(function);

Príklad č. 2: Definovanie funkčného interface pre lambda výraz

Druhý príklad zobrazuje vytvorenie funkčného interface pre základné matematické operácie. Do neho môžeš vkladať výrazy pre sčítanie, odčítanie, násobenie, delenie a metódu operate. Jej úlohou je vziať dve čísla a priradený lambda výraz vypočíta výsledok, ktorý vyzerá nasledovne:

4 + 2 = 6 
4 - 2 = 2
4 * 2 = 8
4 / 2 = 2

Vďaka metóde operate priradený lambda výraz rýchlo a jednoducho vypočíta výsledok.

Do funkčného interface pre základné matematické operácie môžeš vkladať lambda výrazy.

package com.test;

import java.lang. ArithmeticException;

public class LambdaExample2 {
    // Deklarovanie interfejsu pre lamda vyraz
    interface MathOperation {
        int operation(int x, int y);
    }
    // Deklarovanie metody pre matematicku operaciu
    private int operate (int x, int y, MathOperation mathOperation) {
        return mathOperation.operation (x, y);
    }
    // Vypis celej operacie do konzoly.
    public static void printResult(int x, char c, int y, int z) {
        System.out.printf("%d %s %d = %d\n", x, c, y, z);
    }
    public static void main(String[] args) {
        // Bez deklaracie typu
        MathOperation addition = (x, y) -> x + y;
        // S deklaraciou typu (int)
        MathOperation substraction = (int x, int y) -> x - y;
        // S klucovym slovom return (musi byt v krutenych zatvorkach)
        MathOperation multiplication = (x, y) -> { return (x * y); };
        // Viacriadkovy lambda vyraz
        MathOperation division = (x, y) -> {
            if(y != 0)
                return (x / y);
            else
                throw new ArithmeticException("You shouldn't divide a number by zero!");
        };

        LambdaExample2 test = new LambdaExample2();
        int a = 4; int b = 2;
        // Scitanie dvoch cisiel
        printResult(a, '+', b, test.operate (a, b, addition));
        // Odcitanie dvoch cisiel
        printResult(a, '-', b, test.operate (a, b, substraction));
        // Vynasobenie dvoch cisiel
        printResult(a, '*', b, test.operate (a, b, multiplication));
        // Vydelenie dvoch cisiel
        printResult(a, '/', b, test.operate (a, b, division));
    }
}

Príklad č. 3: Sortovanie, filtrovanie a iterovanie kolekcií cez lambda výrazy

Výhodou lambda výrazov je, že znižujú potrebu písania vlastných pomocných metód. Zároveň tiež skracujú a sprehľadňujú kód, čím uľahčujú celú prácu. Sila lambda vyniká najmä pri kombinovaní s inou Java funkcionalitou, napríklad kolekciami.

V nasledujúcom príklade si ukážeme, ako jednoducho triediť, filtrovať a iterovať objekty v kolekcii pomocou lambda výrazov:

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

class Product {
    String name;
    double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
}

public class LambdaExample3 {

    public static Product createProduct(String name, double price) {
        return new Product(name, price);
    }

    public static void main(String[] args) {
        List<Product> products = new ArrayList();
        products.add(createProduct("Chlieb", 1.0));
        products.add(createProduct("Mlieko", 0.5));
        products.add(createProduct("Keksy", 0.8));
        products.add(createProduct("Smotana", 0.4));
        products.add(createProduct ("Cokolada", 0.7));

        // Sortovanie nazvov produktov podla abecedy cez lambdu
        products.sort((p1, p2) -> p1.name.compareTo(p2.name));

        // Vyfiltrovanie produktov s cenou (0.5. 1.0)
        Stream<Product> filteredProducts = products.stream().filter(p -> p.price > 0.5 && p.price < 1.0);

        // Iterovanie v kolekcii
        filteredProducts.forEach(product -> System.out.println(product.name + ": " + product.price));
    }
}

Výstup, ktorý získaš, vyzerá takto:

Cokolada: 0.7
Keksy: 0.8

Lambda výrazy uľahčujú a urýchľujú prácu

Lambda výrazy sú skvelou funkcionalitou v programovacom jazyku Java. Ich používaním sa dá uľahčiť a urýchliť celá práca. Navyše sprehľadňujú kód a otvárajú nové možnosti. Lambda je súčasťou Java od verzie Java 8. Ak teda používaš staršiu verziu, oplatí sa popremýšľať nad jej aktualizáciou.

Pripravili sme pre teba súbory so spomínanými príkladmi Java Lambda, ktoré si môžeš spustiť priamo v Jave. Stiahni si kód tu.

O autorovi

Jozef Wagner

Java Developer Senior

Viac ako 10 rokov programujem v Jave, momentálne pracujem v msg life Slovakia ako Java programátor senior a pomáham zákazníkom implementovať ich požiadavky do poistného softvéru Life Factory. Vo voľnom čase si rád oddýchnem v lese, prípadne si zahrám nejakú dobrú počítačovú hru.

Daj nám o sebe vedieť