Le classi Optional in Java
- Le classi
Optional
,OptionalDouble
,OptionalInt
, eOptionalLong
sono utilizzate per gestire valori che possono essere presenti o meno, evitando l'uso di riferimenti null. - La classe
Optional
fornisce metodi per verificare la presenza di un valore, ottenere il valore se presente, e fornire un valore predefinito quando non è presente un valore. - Le classi
OptionalDouble
,OptionalInt
, eOptionalLong
sono specifiche per i tipi primitivi e forniscono metodi simili a quelli diOptional
. - Queste classi aiutano a prevenire le eccezioni di tipo
NullPointerException
e migliorano la leggibilità del codice. - Le classi implementano metodi come
isPresent()
,get()
,orElse()
, emap()
per lavorare con i valori in modo sicuro e conciso.
Le classi Optional
A partire da JDK 8, la libreria standard di Java include le classi Optional
, OptionalDouble
, OptionalInt
, e OptionalLong
. Queste classi sono state introdotte per affrontare il problema della gestione dei valori che possono essere presenti o meno, evitando l'uso di riferimenti null
che possono causare eccezioni di tipo NullPointerException
.
In passato, normalmente si usava il valore null
per indicare che nessun valore è presente. Tuttavia, questo può portare a eccezioni NullPointerException
se viene fatto un tentativo di dereferenziare un riferimento null
. Di conseguenza, erano necessari controlli frequenti per verificare se un valore null
era presente per evitare di generare un'eccezione. Queste classi forniscono un modo migliore per gestire tali situazioni.
La prima e più generale di queste classi è Optional
. Per questa ragione, è il focus principale di questa lezione. È mostrata qui:
class Optional<T>
Si tratta di una classe generica, infatti T
specifica il tipo di valore memorizzato. È importante capire che un'istanza Optional
può contenere un valore di tipo T
o essere vuota. In altre parole, un oggetto Optional
non contiene necessariamente un valore.
Optional
non definisce alcun costruttore, ma definisce diversi metodi che permettono di lavorare con gli oggetti Optional
. Ad esempio, puoi determinare se un valore è presente, ottenere il valore se è presente, ottenere un valore predefinito quando nessun valore è presente, e costruire un valore Optional
.
I metodi Optional
sono mostrati nella tabella seguente:
Metodo | Descrizione |
---|---|
static <T> Optional<T> empty() |
Restituisce un oggetto per cui isPresent() restituisce false . |
boolean equals(Object opzionale) |
Restituisce true se l'oggetto invocante è uguale a opzionale. Altrimenti, restituisce false . |
Optional<T> filter(Predicate<? super T> condizione) |
Restituisce un'istanza Optional che contiene lo stesso valore dell'oggetto invocante se quel valore soddisfa condizione. Altrimenti, viene restituito un oggetto vuoto. |
Optional<U> flatMap(Function<? super T, Optional<U>> funzioneMappa) |
Applica la funzione di mappatura specificata da funzioneMappa all'oggetto invocante se quell'oggetto contiene un valore e restituisce il risultato. Restituisce un oggetto vuoto altrimenti. |
T get() |
Restituisce il valore nell'oggetto invocante. Tuttavia, se nessun valore è presente, viene lanciata NoSuchElementException . |
int hashCode() |
Restituisce un codice hash per il valore nell'oggetto invocante. Restituisce 0 se non c'è valore. |
void ifPresent(Consumer<? super T> funz) |
Chiama funz se un valore è presente nell'oggetto invocante, passando l'oggetto a funz. Se nessun valore è presente, non avviene alcuna azione. |
void ifPresentOrElse(Consumer<? super T> funz, Runnable seVuoto) |
Chiama funz se un valore è presente nell'oggetto invocante, passando l'oggetto a funz . Se nessun valore è presente, seVuoto verrà eseguito. |
boolean isEmpty() |
Restituisce true se l'oggetto invocante non contiene un valore. Restituisce false se un valore è presente. |
boolean isPresent() |
Restituisce true se l'oggetto invocante contiene un valore. Restituisce false se nessun valore è presente. |
U Optional<U> map(Function<? super T, ? extends U> funzioneMappa) |
Applica la funzione di mappatura specificata da funzioneMappa all'oggetto invocante se quell'oggetto contiene un valore e restituisce il risultato. Restituisce un oggetto vuoto altrimenti. |
static <T> Optional<T> of(T val) |
Crea un'istanza Optional che contiene val e restituisce il risultato. Il valore di val non deve essere null. |
static <T> Optional<T> ofNullable(T val) |
Crea un'istanza Optional che contiene val e restituisce il risultato. Tuttavia, se val è null, allora viene restituita un'istanza Optional vuota. |
Optional<T> or(Supplier<? extends Optional<? extends T>> funz) |
Se nessun valore è presente nell'oggetto invocante, chiama funz per costruire e restituire un'istanza Optional che contiene un valore. Altrimenti, restituisce un'istanza Optional che contiene il valore dell'oggetto invocante. |
T orElse(T valPredefinito) |
Se l'oggetto invocante contiene un valore, il valore viene restituito. Altrimenti, viene restituito il valore specificato da valPredefinito . |
T orElseGet(Supplier<? extends T> ottieniFunz) |
Se l'oggetto invocante contiene un valore, il valore viene restituito. Altrimenti, viene restituito il valore ottenuto da ottieniFunz . |
T orElseThrow() |
Restituisce il valore nell'oggetto invocante. Tuttavia, se nessun valore è presente, viene lanciata NoSuchElementException . |
<X extends Throwable> T orElseThrow(Supplier<? extends X> funzEcc) throws X |
Restituisce il valore nell'oggetto invocante. Tuttavia, se nessun valore è presente, viene lanciata l'eccezione generata da funzEcc . |
Stream<T> stream() |
Restituisce uno stream che contiene il valore dell'oggetto invocante. Se nessun valore è presente, lo stream non conterrà valori. |
String toString() |
Restituisce una stringa corrispondente all'oggetto invocante. |
Il modo migliore per comprendere Optional
è attraversare un esempio che utilizza i suoi metodi principali.
Alla base di Optional
ci sono isPresent()
e get()
. È possibile determinare se un valore è presente chiamando isPresent()
. Se un valore è disponibile, restituirà true
. Altrimenti, viene restituito false
. Se un valore è presente in un'istanza Optional
, è possibile ottenerlo chiamando get()
. Tuttavia, se si chiama get()
su un oggetto che non contiene un valore, viene lanciata NoSuchElementException
. Per questo motivo, si dovrebbe sempre prima confermare che un valore è presente prima di chiamare get()
su un oggetto Optional
. A partire da JDK 10, la versione senza parametri di orElseThrow()
può essere utilizzata al posto di get()
, e il suo nome aggiunge chiarezza all'operazione.
Naturalmente, dover chiamare due metodi per recuperare un valore aggiunge overhead a ogni accesso. Fortunatamente, Optional
definisce metodi che combinano il controllo per un valore con il recupero del valore. Uno di questi metodi è orElse()
. Se l'oggetto su cui viene chiamato contiene un valore, il valore viene restituito. Altrimenti, viene restituito un valore predefinito.
Optional
non definisce alcun costruttore. Invece, utilizzeremo uno dei suoi metodi per creare un'istanza. Ad esempio, è possibile creare un'istanza Optional
con un valore specificato utilizzando of()
. È possibile creare un'istanza di Optional
che non contiene un valore utilizzando empty()
.
Il seguente programma dimostra questi metodi:
// Dimostra diversi metodi Optional<T>
import java.util.*;
class DemoOptional {
public static void main(String[] args) {
// Creazione di un Optional di tipo String ma vuoto
Optional<String> nessuno = Optional.empty();
// Creazione di un Optional di tipo String con un valore
// Utilizza Optional.of() per creare un Optional con un valore non nullo
Optional<String> haValore = Optional.of("ABCDEFG");
if (nessuno.isPresent()) {
System.out.println("Questo non verrà visualizzato");
} else {
System.out.println("nessuno non ha valore");
}
if (haValore.isPresent()) {
System.out.println("La stringa in haValore è: " +
haValore.get());
} else {
System.out.println("haValore non ha valore");
}
// Ottiene un valore predefinito se l'Optional è vuoto
String strPred = nessuno.orElse("Stringa Predefinita");
System.out.println(strPred);
}
}
L'output è mostrato qui:
nessuno non ha valore
La stringa in haValore è: ABCDEFG
Stringa Predefinita
Come mostra l'output, un valore può essere ottenuto da un oggetto Optional
solo se ne è presente uno. Questo meccanismo di base consente a Optional
di prevenire le eccezioni di puntatore nullo.
Le classi OptionalDouble
, OptionalInt
e OptionalLong
funzionano molto come Optional
, tranne che sono progettate espressamente per l'uso su valori double
, int
e long
, rispettivamente. Come tali, specificano i metodi getAsDouble()
, getAsInt()
e getAsLong()
, rispettivamente, piuttosto che get()
. Inoltre, non supportano i metodi filter()
, ofNullable()
, map()
, flatMap()
e or()
.