Cos'è facoltativo?
Il parametro Opzionale viene utilizzato per trasportare oggetti e consentire la gestione dei riferimenti null da parte di varie API. Diamo un'occhiata allo snippet di codice:Coffee coffee = new Coffee();
Integer quantity = coffee.getSugar().getQuantity();
Abbiamo un'istanza Coffee in cui otteniamo dello zucchero da un'istanza dell'oggetto Sugar . Se assumiamo che il valore della quantità non sia mai stato impostato nel costruttore Coffee , allora coffee.getSugar().getQuantity() restituirà una NullPointerException . Naturalmente, possiamo sempre utilizzare i buoni vecchi controlli null per risolvere il problema.
Coffee coffee = new Coffee();
Integer quantity = 0;
if (coffee.getSugar() != null) {
quantity = coffee.getSugar().getQuantity();
}
Ora sembra che vada tutto bene. Ma quando si scrive codice Java, è meglio evitare di implementare controlli null . Vediamo come è possibile farlo utilizzando Opzionale.
Come creare Opzionale
Esistono tre modi per creare oggetti opzionali:-
of(valore T) — istanziazione di un oggetto facoltativo non nullo. Tieni presente che l'uso di of() per fare riferimento a un oggetto null genererà una NullPointerException .
-
ofNullable(valore T) : crea un valore opzionale per un oggetto che può essere null.
-
vuoto() - Crea un'istanza opzionale che rappresenta un riferimento a null .
// пример использования Optional.of(T Value)
String name = "foo";
Optional<String> stringExample = Optional.of(name)
// пример использования Optional.ofNullable(T Value)
Integer age = null;
Optional<Integer> integerExample= Optional.ofNullable(age)
// пример использования Optional.empty()
Optional<Object> emptyExample = Optional.empty();
Quindi hai un oggetto opzionale. Ora diamo un'occhiata ai due metodi principali per Opzionale:
-
isPresent() : questo metodo indica se l'oggetto opzionale contiene un valore non nullo.
-
get() : recupera il valore per Opzionale con il valore corrente. Tieni presente che chiamare get() su un Opzionale vuoto risulterà in una NullPointerException .
Miglioramento del controllo null con facoltativo
Allora come possiamo migliorare il codice sopra? Con Optional possiamo comprendere la presenza di un oggetto utilizzando isPresent() e recuperarlo utilizzando get() . Iniziamo impacchettando il risultato di coffee.getSugar() con Optional e utilizzando il metodo isPresent() . Questo ci aiuterà a determinare se getSugar() restituisce null.Coffee coffee = new Coffee();
Optional<String> sugar = Optional.ofNullable(coffee.getSugar());
int quantity = 0;
if (sugar.isPresent()) {
Sugar sugar = sugar.get();
int quantity = sugar.getQuantity();
}
Guardando questo esempio, impacchettare il risultato di coffee.getSugar() in Optional non sembra aggiungere alcun valore, ma piuttosto aggiunge problemi. Possiamo migliorare il risultato utilizzando quelle che considero le mie funzioni preferite della classe Opzionale:
-
map(Function<? super T,? extends U> mapper) - Mappa il valore contenuto in Opzionale alla funzione fornita. Se il parametro Opzionale è vuoto, map() restituirà Opzionale.empty() .
-
orElse(T other) è una versione “speciale” del metodo get() . Può ottenere il valore contenuto in Opzionale. Tuttavia, nel caso di un Optional vuoto, restituirà il valore passato al metodo orElse() .
Coffee coffee = new Coffee();
Integer quantity = Optional.ofNullable(coffee.getSugar())
.map(it -> it.getQuantity())
.orElse(0);
Questo è davvero fantastico, almeno penso di sì. Ora, se in caso di valore vuoto non vogliamo restituire il valore predefinito, allora dobbiamo lanciare qualche tipo di eccezione. orElseThrow(Supplier<? extends X>ExceptionSupplier) restituisce il valore contenuto nei parametri Opzionali o genera un'eccezione se l'Opzionale è vuoto.
Coffee coffee = new Coffee();
Integer quantity = Optional.ofNullable(coffee.getSugar())
.map(it -> it.getQuantity())
.orElseThrow(IllegalArgumentException::new);
Come puoi vedere, l'opzione opzionale offre diversi vantaggi:
- astrae i controlli nulli
- fornisce un'API per la gestione di oggetti null
- consente all'approccio dichiarativo di esprimere ciò che si sta ottenendo
Come diventare efficaci con gli Opzionali
Nel mio lavoro utilizzo Opzionale come tipo restituito quando un metodo può restituire uno stato "nessun risultato". Di solito lo uso quando definisco i tipi restituiti per i metodi.Optional<Coffee> findByName(String name) {
...
}
A volte questo non è necessario. Ad esempio, se ho un metodo che restituisce un int , come getQuantity() nella classe Sugar , allora il metodo potrebbe restituire 0 se il risultato è null per rappresentare "nessuna quantità". Ora, sapendo questo, possiamo pensare che il parametro Sugar nella classe Coffee possa essere rappresentato come Opzionale. A prima vista sembra una buona idea perché, in teoria, non è necessario che lo zucchero sia presente nel caffè. Tuttavia, è qui che vorrei affrontare quando non utilizzare Opzionale. Dovremmo evitare di utilizzare Opzionale nei seguenti scenari:
-
Come tipi di parametri per POJO , come DTO . Gli facoltativi non sono serializzabili, quindi utilizzarli in un POJO rende l'oggetto non serializzabile.
-
Come argomento di metodo. Se l'argomento di un metodo può essere null , dal punto di vista del puro codice, passare null è comunque preferibile rispetto a passare Optional. Inoltre, puoi creare metodi di sovraccarico per gestire in modo astratto l'assenza di un argomento del metodo null.
-
Per rappresentare un oggetto Collection mancante. Le raccolte possono essere vuote, quindi una Collection vuota , come un Set o una List vuota , deve essere utilizzata per rappresentare una Collection senza valori.
GO TO FULL VERSION