Was ist ein Supplier?

Ein Supplier ist ein functional interface, das verwendet werden kann, um die Ausführung von Code zeitlich zu versetzen oder Streams mehrfach zu verwenden. Seine Methode get() greift auf den Inhalt des Suppliers zu.

Versetzte Abfrage einer Methodenausführung

Das Beispiel demonstriert die zeitlich versetzte Methodenausführung anhand eines LocalTime-Objektes.

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.function.Supplier;

public class SupplierBsp {

    public static void main(String[] args) {
        printTime();
    }
    
    private static void printTime() {
        DateTimeFormatter f = DateTimeFormatter.ofPattern("HH:mm:ss");
        LocalTime jetzt = LocalTime.now();
        Supplier<LocalTime> jetztSuppl = LocalTime::now;
        System.out.println(jetzt.format(f)); // 20:46:12 
        System.out.println(jetztSuppl.get().format(f)); // 20:46:12
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(jetzt.format(f)); // 20:46:12
        System.out.println(jetztSuppl.get().format(f)); // 20:46:15
    }
}

In Zeile [9] wird ein LocalTime-Objekt erzeugt und über dessen statische Methode now() der momentane Zeitpunkt erfasst. Das Ergebnis wird in einer Variablen jetzt vom Typ LocalTime gespeichert. Das gleiche geschieht anschließend in Zeile [10] mit dem Unterschied, dass die Speicherung in einer Variablen vom Typ Supplier erfolgt. Die darauf erfolgende Ausgabe beider Variablen zeigt selbstverständlich identische Ergebnisse [11, 12].

Nach Pausieren des ausführenden Threads wird der Inhalt beider Variablen erneut abgefragt und ausgegeben. Im Unterschied zur Ausgabe von jetzt in Zeile [18], die das selbe Ergebnis wie in Zeile [15] erzeugt, zeigt der vom Supplier gelieferte Zeitstempel, dass dieser offensichtlich erst nach Pausieren des Threads erzeugt wurde und nicht zum Zeitpunkt der Initialisierung des Supplier in Zeile [14]. Dies zeigt, dass die Methode LocalTime.now() erst zum Zeitpunkt seiner Ausgabe ausgeführt wird. [19].

Bedingte Ausführung durch Übergabe an ein Optional

Die Klasse Optional definiert einige Methoden, die einen Supplier als Parameter entgegennehmen. Das Besondere daran ist, dass die Verarbeitung des Suppliers nur dann erfolgt, wenn das Optional leer ist.

private static void printTimeByOptional() {
    DateTimeFormatter f = DateTimeFormatter.ofPattern("HH:mm:ss");
    LocalTime jetzt = LocalTime.now();
    Supplier<LocalTime> jetztSuppl = LocalTime::now;
    Optional<LocalTime> op = Optional.of(jetzt);
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Optional with DateTime: " + op.get().format(f)); // 19:53:25
    System.out.println("Optional with Supplier: " + op.orElseGet(jetztSuppl).format(f)); // 19:53:25
    op = Optional.empty(); // Optional leeren
    System.out.println("Optional is empty:  " + op.isEmpty()); // true
    System.out.println("Empty Optional with Supplier: " + op.orElseGet(jetztSuppl).format(f)); // 19:53:28
    System.out.println("Optional is empty:  " + op.isEmpty()); // true
}

Nach Bilden eines LocalTime-Objektes der aktuellen Zeit [3] und einem Supplier mit gleichem Inhalt [4], wird mit dem LocalTime-Objekt ein Optional erzeugt [5].
Nach Pausieren des ausführenden Threads wird der Wert des Optionals mittels get() ermittelt und ausgegeben [11]. Die darauf folgende Übergabe des Suppliers an die Optional-Methode orElseGet() liefert trotz des pausierten Threads das selbe Ergebnis [12]. Dies verweist darauf, dass die Methode orElseGet() trotz des übergebenen Suppliers den bisherigen Inhalt des Optionals zurückgibt. Der Supplier wird erst ausgeführt, nachdem das Optional im nächsten Schritt geleert wurde [15].
Die letzte Zeile der Methode zeigt schließlich, dass das Optional auch nach Ausführung des Suppliers weiterhin leer bleibt [16].

Mehrfachnutzung eines Streams

Ein Supplier ermöglicht auch die mehrfache Nutzung eines Streams. Das folgende Beispiel demonstriert dies anhand der Ausgabe einer gefilterten List.

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

public class SupplierBsp {

    public static void main(String[] args) {
        List<String> list = List.of("Motobecane", "Brough Superior", "Indian", "Benelli", "Megola", "Scott", "Vincent", "Maico");
        Stream<String> stream = filterMopeds(list);
        stream.forEach(System.out::println);
        System.out.println(stream.count()); // java.lang.IllegalStateException
    }

    private static Stream<String> filterMopeds(List<String> s) {
        Stream<String> stream = s.stream().map(w -> w.toLowerCase()).filter(w -> w.startsWith("m"));
        return stream;
    }
}

In Zeile [8] wird eine List mit String-Elementen erzeugt, die an die Methode filterMopeds() als Parameter übergeben wird. Sie erzeugt einen Stream, der einige Elemente herausfiltert und diese wiederum als Stream zurückgibt.
In den Zeilen [10, 11] wird dieser Stream weiterverwendet, um die Elemente selbst, sowie in einem weiteren Schritt deren Anzahl auszugeben.

Das Ergebnis zeigt die Ausgabe dreier historischer Motorradmarken gefolgt von einer IllegalStateException. Die Ursache liegt darin, dass ein Stream nur ein Mal verarbeitet werden kann, sodass die Anzahl der Elemente nicht ermittelt werden kann [11].

Arbeitet man die Methode so um, dass ein Supplier<Stream<String>> zurückgegeben wird, kann der Stream bedenkenlos zwei Mal nacheinander weiterverarbeitet werden:

private static Supplier<Stream<String>> filterMopedsBySuppl(List<String> s) {
    Supplier<Stream<String>> suppl = () -> s.stream().map(w -> w.toLowerCase()).filter(w -> w.startsWith("m"));
    return suppl;
}

//...

Supplier<Stream<String>> supplStream = filterMopedsBySuppl(list);
supplStream.get().forEach(System.out::println);
System.out.println(supplStream.get().count());

// Ausgabe:
// motobecane
// megola
// maico
// 3

Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.