Lambda väljendid

Kirjeldus, Süntaks

Lambda väljend ehk anonüümne funktsioon on kood, mis võtab sisendiks mingid parameetrid ning tagastab väärtuse. Lambda väljenditel puudub nimi ning neid saab otse meetodi sees implementeerida.

Lambda väljendeid saab kasutada alates Java 8-st.

Ühe parameetri ja kohese tagastusega anonüümset funktsiooni kirjutatakse järgnevalt:

// Simplest lamba expression form:
// parameter -> expression

// Example: Print out each string in list using lambda expression
List<String> list = Arrays.asList("foo", "bar", "foobar");
list.forEach(str -> System.out.println(str));   // Lambda expression
list.forEach(System.out::println);              // One parameter expressions can be even more simplified

Nagu näha, siis ühe parameetrilisi väljendeid saab veel lihtsamalt kirjutada, kasutades võtet nimega "Method reference". "Method reference" on otsene viis lambda väljenditele meetodite välja kutsumiseks.

Parameetreid võib olla ka rohkem kui üks:

// Multi parameter lambda expression form:
// (p1, p2) -> expression

// Example: Add together Key-Value pair from map using lambda expression
Map<Integer, String> map = Map.of(1, "Player 1", 2, "Player 2", 3, "Player 3");
map.forEach((key, value) -> System.out.println("id: " + key + " - name: " + value));

Väljendid peavad koheselt tagastama midagi. Kui tekib vajadus raskema loogika läbi viimiseks, saab lambda juurde lisada ka koodiploki, kasutades logelisi sulge.

// Lambda with code-block form:
// parameter -> { /* Code goes here */ }

// Example: Decide randomly whether child in list is nice or naughty using lambda expression
Random random = new Random();
List<String> list = Arrays.asList("Aadu", "Beedu", "Ceedu", "Deedu");
list.forEach(str -> {
    if (random.nextInt(10) > 5) {
        System.out.println(str + " is a nice child and gets a present");
    } else {
        System.out.println(str + " is a naughty child and gets coal");
    }
});

Funktsionaalne liides

Funktsionaalne liides (functional interface) on liides, millel on ainult üks abstraktne meetod (piirang puudub staatilistel ja tavalistel meetoditel). Funktsionaalsete liideste eeliseks on puhtam, otsekohsesem, loetavam kood.

Javas mõned funktsionaalsed liidesed oleksid näiteks Runnable, Callable, Comparable, Predicate, Consumer, Function ja Supplier.

Enne Java 8 pidi funktsionaalseid liideseid deklaleerida siseklassidena:

// Functional interface example using threads and Runnable
new Thread(new Runnable() {
    @Override
    public void run() {
        // Code goes here
    }
}).start();

Alates Java 8-st on võimalik kasutada lambda väljendeid, et deklaleerida funktsionaalseid liideseid.

// Functional interface example using threads, Runnable and lambda expression
new Thread(() -> {
    // Code goes here
}).start();

Funktsionaalset liidest koostades võiks juurde lisada ka informatiivse annotatsiooni @FunctionalInterface, mis annab märku, et antud liides peaks olema just seda tüüpi. Antud näites loome funktsionaalse liidese, mille ülesanne on võtta ruutu sisendina saadud number. Me ei tea, mis tüüpi number see saab olema ehk deklaleerime selle kui geneerilise tüübina. Klassis Example implementeerime loodud liidese ning anname ette ka numbritüübi, antud juhul Integer ehk täisarv.

@FunctionalInterface
interface SquareRoot<T extends Number> {
    T run(T a);
}

public class Example {
    public static void main(String[] args) {
        SquareRoot<Integer> squareRoot = (Integer x) -> x * x;
        System.out.println(squareRoot.run(5));  // 25
    }
}

Uuri lisaks:

Lambda expression: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#approach8

Functional interface: https://docs.oracle.com/en/java/javase/21/docs//api/java.base/java/util/function/package-summary.html