Supplier în Java

Un „furnizor” de valori: nu primește nimic și returnează o valoare când apelezi get; util pentru valori create la nevoie.

Sintaxă
import java.util.function.Supplier;

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Ce face Supplier

Supplier<T> este o funcție fără parametri care returnează un T. Apelezi get() ca să primești valoarea. Fiecare apel poate da o valoare nouă (de exemplu un obiect nou sau următorul număr).

Avantajul principal este amânarea: valoarea se calculează doar dacă e nevoie. optional.orElseGet(supplier) rulează furnizorul doar când Optional e gol, iar Stream.generate(supplier) și Collectors.toCollection(ArrayList::new) primesc tot un Supplier. O referință la constructor, ArrayList::new, este un Supplier.

Ce returnează

get returnează o valoare de tip T.

Exemple

Exemplul 1: Furnizori de valori

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        Supplier<String> mesaj = () -> "Bine ai venit pe dexblog.ro!";
        Supplier<List<String>> listaNoua = ArrayList::new;

        System.out.println(mesaj.get());
        List<String> a = listaNoua.get();
        List<String> b = listaNoua.get();
        a.add("Ana");
        System.out.println(a + " " + b + " același obiect? " + (a == b));
    }
}

Rezultat

Bine ai venit pe dexblog.ro!
[Ana] [] același obiect? false

Exemplul 2: Calcul amânat cu orElseGet

orElse calculează valoarea de rezervă mereu; orElseGet apelează furnizorul doar când e nevoie.

import java.util.Optional;
import java.util.function.Supplier;

public class Main {
    static String valoareImplicita() {
        System.out.println("  (calculez valoarea implicită...)");
        return "București";
    }

    public static void main(String[] args) {
        Optional<String> oras = Optional.of("Iași");
        Supplier<String> rezerva = Main::valoareImplicita;

        System.out.println("orElse:");
        System.out.println(oras.orElse(valoareImplicita()));
        System.out.println("orElseGet:");
        System.out.println(oras.orElseGet(rezerva));
        System.out.println("orElseGet pe Optional gol:");
        System.out.println(Optional.<String>empty().orElseGet(rezerva));
    }
}

Rezultat

orElse:
  (calculez valoarea implicită...)
Iași
orElseGet:
Iași
orElseGet pe Optional gol:
  (calculez valoarea implicită...)
București

Greșeli frecvente

  • Folosești orElse(calculScump()): calculul se face chiar dacă nu e nevoie de el. Folosește orElseGet(() -> calculScump()).
  • Crezi că get() returnează mereu aceeași valoare. Depinde de furnizor: ArrayList::new creează o listă nouă la fiecare apel.

Comenzi înrudite

  • Consumer: O acțiune care primește o valoare și nu returnează nimic (afișează, salvează, trimite); o rulezi cu accept.
  • Function: O funcție care primește o valoare de tip T și returnează una de tip R; o apelezi cu apply.
  • Stream.iterate: Creează un stream din formule: iterate pornește de la o valoare și aplică un pas, generate cere fiecare valoare unui Supplier.
  • Collectors.toList: Adună elementele stream-ului într-o listă (toList), într-o mulțime fără duplicate (toSet) sau într-o listă ce nu se poate modifica.