Ce face Optional
Optional<T> este un obiect care fie conține o valoare de tip T, fie este gol. Metodele care pot să nu găsească nimic îl returnează în loc de null: stream.findFirst(), stream.max(...), propriile tale metode de căutare. Tipul returnat spune clar „rezultatul poate lipsi”.
Nu scoți valoarea direct, ci spui ce se întâmplă în ambele cazuri: orElse(rezerva), orElseGet(...), orElseThrow(), ifPresent(...), ifPresentOrElse(...). Poți transforma valoarea fără să o scoți: map, flatMap, filter.
Optional este gândit pentru valori de retur. Nu îl folosi pentru câmpuri, parametri sau elemente de colecții; acolo o colecție goală sau o valoare implicită sunt mai potrivite. Pentru primitive există OptionalInt, OptionalDouble, OptionalLong.
Parametri
| Parametru | Descriere |
|---|---|
T |
Tipul valorii din interior. |
Ce returnează
Un obiect Optional, plin sau gol.
Exemple
Exemplul 1: Căutarea unui utilizator
import java.util.Map;
import java.util.Optional;
public class Main {
static final Map<String, String> emailuri = Map.of("ana", "ana@exemplu.ro", "radu", "radu@exemplu.ro");
static Optional<String> gasesteEmail(String utilizator) {
return Optional.ofNullable(emailuri.get(utilizator));
}
public static void main(String[] args) {
System.out.println(gasesteEmail("ana"));
System.out.println(gasesteEmail("elena"));
System.out.println(gasesteEmail("radu").orElse("fără email"));
System.out.println(gasesteEmail("elena").orElse("fără email"));
}
}
Rezultat
Optional[ana@exemplu.ro]
Optional.empty
radu@exemplu.ro
fără email
Exemplul 2: Optional din stream-uri
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<String> orase = List.of("Iași", "Cluj", "Constanța", "Craiova");
Optional<String> primulCuC = orase.stream().filter(o -> o.startsWith("C")).findFirst();
Optional<String> primulCuZ = orase.stream().filter(o -> o.startsWith("Z")).findFirst();
primulCuC.ifPresent(o -> System.out.println("Găsit: " + o));
System.out.println("Cu Z: " + primulCuZ.isPresent());
System.out.println("Cel mai lung: " + orase.stream().max(Comparator.comparingInt(String::length)).orElseThrow());
}
}
Rezultat
Găsit: Cluj
Cu Z: false
Cel mai lung: Constanța
Exemplul 3: Lanț de transformări
map lucrează doar dacă există valoare; altfel tot lanțul rămâne gol și ajunge la orElse.
import java.util.Optional;
public class Main {
record Adresa(String oras) {}
record Client(String nume, Adresa adresa) {}
static String orasMajuscule(Client c) {
return Optional.ofNullable(c)
.map(Client::adresa)
.map(Adresa::oras)
.map(String::toUpperCase)
.orElse("NECUNOSCUT");
}
public static void main(String[] args) {
System.out.println(orasMajuscule(new Client("Ana", new Adresa("Iași"))));
System.out.println(orasMajuscule(new Client("Radu", null)));
System.out.println(orasMajuscule(null));
}
}
Rezultat
IAȘI
NECUNOSCUT
NECUNOSCUT
Greșeli frecvente
- Apelezi
get()fără să verifici. Pe unOptionalgol aruncăNoSuchElementException; foloseșteorElse,orElseThrowsauifPresent. - Returnezi
nulldintr-o metodă al cărei tip esteOptional. ReturneazăOptional.empty(). - Folosești
Optionalpentru câmpuri și parametri. Nu este gândit pentru asta și complică codul.
Comenzi înrudite
Optional.of: of(x) creează un Optional cu o valoare sigur prezentă, ofNullable(x) unul care e gol dacă x este null, empty() unul gol.Optional.orElse: orElse returnează valoarea sau o rezervă dată; orElseGet calculează rezerva cu o funcție, doar când e nevoie.Optional.map: map transformă valoarea din Optional (dacă există) și o pune într-un Optional nou; flatMap face la fel pentru funcții care returnează deja Optional.Optional.ifPresent: ifPresent execută o acțiune doar dacă există valoare; ifPresentOrElse are și o acțiune separată pentru cazul gol.Stream.findFirst: Returnează primul element din stream (findFirst) sau oricare element (findAny), ca Optional.Map.get: get returnează valoarea unei chei sau null dacă lipsește; getOrDefault returnează o valoare de rezervă în loc de null.