Java Language
Opzionale
Ricerca…
introduzione
Optional
è un oggetto contenitore che può contenere o meno un valore non nullo. Se è presente un valore, isPresent()
restituirà true
e get()
restituirà il valore.
Vengono forniti ulteriori metodi che dipendono dalla presenza del valore contenuto, ad esempio orElse()
, che restituisce un valore predefinito se value non è presente e ifPresent()
che esegue un blocco di codice se il valore è presente.
Sintassi
- Optional.empty () // Crea un'istanza opzionale vuota.
- Optional.of (valore) // Restituisce un Facoltativo con il valore non null specificato. Una NullPointerException verrà lanciata se il valore passato è nullo.
- Optional.ofNullable (valore) // Restituisce un Facoltativo con il valore specificato che può essere nullo.
Restituisce il valore predefinito se Opzionale è vuoto
Non utilizzare semplicemente Optional.get()
poiché potrebbe generare NoSuchElementException
. I metodi Optional.orElse(T)
e Optional.orElseGet(Supplier<? extends T>)
forniscono un modo per fornire un valore predefinito nel caso in cui l'opzione sia vuota.
String value = "something";
return Optional.ofNullable(value).orElse("defaultValue");
// returns "something"
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue());
// returns "something" (never calls the getDefaultValue() method)
String value = null;
return Optional.ofNullable(value).orElse("defaultValue");
// returns "defaultValue"
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue());
// calls getDefaultValue() and returns its results
La differenza cruciale tra orElse
e orElseGet
è che quest'ultimo viene valutato solo quando l'opzione è vuota mentre l'argomento fornito a quello precedente viene valutato anche se l'opzione non è vuota. orElse
, orElse
dovrebbe essere utilizzato solo per le costanti e mai per fornire valore basato su qualsiasi tipo di calcolo.
Carta geografica
Utilizza il metodo map()
di Optional
per lavorare con valori che potrebbero essere null
senza fare controlli null
espliciti:
(Si noti che le operazioni map()
e filter()
vengono valutate immediatamente, a differenza delle loro controparti Stream che vengono valutate solo su un'operazione terminale .)
Sintassi:
public <U> Optional<U> map(Function<? super T,? extends U> mapper)
Esempi di codice:
String value = null;
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "NONE"
String value = "something";
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "SOMETHING"
Poiché Optional.map () restituisce un opzionale vuoto quando la sua funzione di mappatura restituisce null, è possibile concatenare diverse operazioni map () come una forma di dereferenziazione null-safe. Questo è anche noto come concatenamento sicuro .
Considera il seguente esempio:
String value = foo.getBar().getBaz().toString();
Qualsiasi getBar
, getBaz
e toString
possono potenzialmente lanciare una NullPointerException
.
Ecco un modo alternativo per ottenere il valore da toString()
usando Optional
:
String value = Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.orElse("");
Ciò restituirà una stringa vuota se una qualsiasi delle funzioni di mapping ha restituito null.
Di seguito è riportato un altro esempio, ma leggermente diverso. Stampa il valore solo se nessuna delle funzioni di mappatura ha restituito nulla.
Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.ifPresent(System.out::println);
Getta un'eccezione, se non c'è valore
Utilizzare il metodo orElseThrow()
di Optional
per ottenere il valore contenuto o generare un'eccezione, se non è stata impostata. È simile alla chiamata get()
, tranne per il fatto che consente tipi di eccezioni arbitrarie. Il metodo accetta un fornitore che deve restituire l'eccezione da lanciare.
Nel primo esempio, il metodo restituisce semplicemente il valore contenuto:
Optional optional = Optional.of("something");
return optional.orElseThrow(IllegalArgumentException::new);
// returns "something" string
Nel secondo esempio, il metodo genera un'eccezione perché non è stato impostato un valore:
Optional optional = Optional.empty();
return optional.orElseThrow(IllegalArgumentException::new);
// throws IllegalArgumentException
È inoltre possibile utilizzare la sintassi lambda se è necessario lanciare un'eccezione con il messaggio:
optional.orElseThrow(() -> new IllegalArgumentException("Illegal"));
Filtro
filter()
viene utilizzato per indicare che si desidera il valore solo se corrisponde al proprio predicato.
Pensalo come if (!somePredicate(x)) { x = null; }
.
Esempi di codice:
String value = null;
Optional.ofNullable(value) // nothing
.filter(x -> x.equals("cool string"))// this is never run since value is null
.isPresent(); // false
String value = "cool string";
Optional.ofNullable(value) // something
.filter(x -> x.equals("cool string"))// this is run and passes
.isPresent(); // true
String value = "hot string";
Optional.ofNullable(value) // something
.filter(x -> x.equals("cool string"))// this is run and fails
.isPresent(); // false
Utilizzo di contenitori opzionali per tipi di numeri primitivi
OptionalDouble
, OptionalInt
e OptionalLong
funzionano come Optional
, ma sono specificamente progettati per includere tipi primitivi:
OptionalInt presentInt = OptionalInt.of(value);
OptionalInt absentInt = OptionalInt.empty();
Poiché i tipi numerici hanno un valore, non esiste una gestione speciale per null. I contenitori vuoti possono essere controllati con:
presentInt.isPresent(); // Is true.
absentInt.isPresent(); // Is false.
Allo stesso modo, esistono stenografie per aiutare la gestione del valore:
// Prints the value since it is provided on creation.
presentInt.ifPresent(System.out::println);
// Gives the other value as the original Optional is empty.
int finalValue = absentInt.orElseGet(this::otherValue);
// Will throw a NoSuchElementException.
int nonexistentValue = absentInt.getAsInt();
Esegui il codice solo se è presente un valore
Optional<String> optionalWithValue = Optional.of("foo");
optionalWithValue.ifPresent(System.out::println);//Prints "foo".
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(System.out::println);//Does nothing.
Fornisci un valore predefinito usando un fornitore
Il normale metodo orElse
riceve un Object
, quindi potresti chiedervi perché esiste un'opzione per fornire un Supplier
qui (il metodo orElseGet
).
Tenere conto:
String value = "something";
return Optional.ofNullable(value)
.orElse(getValueThatIsHardToCalculate()); // returns "something"
Chiamerebbe comunque getValueThatIsHardToCalculate()
anche se il risultato non è utilizzato in quanto l'opzionale non è vuoto.
Per evitare questa penalità fornisci un fornitore:
String value = "something";
return Optional.ofNullable(value)
.orElseGet(() -> getValueThatIsHardToCalculate()); // returns "something"
In questo modo getValueThatIsHardToCalculate()
verrà chiamato solo se l' Optional
è vuota.
FlatMap
flatMap
è simile alla map
. La differenza è descritta da javadoc come segue:
Questo metodo è simile alla
map(Function)
, ma il mapper fornito è uno il cui risultato è già unOptional
e, se invocato,flatMap
non lo avvolge con unOptional
.
In altre parole, quando si concatena una chiamata al metodo che restituisce un Optional
, usando Optional.flatMap
evita di creare Optionals
nidificati.
Ad esempio, date le seguenti classi:
public class Foo {
Optional<Bar> getBar(){
return Optional.of(new Bar());
}
}
public class Bar {
}
Se usi Optional.map
, otterrai un Optional
nidificata; cioè Optional<Optional<Bar>>
.
Optional<Optional<Bar>> nestedOptionalBar =
Optional.of(new Foo())
.map(Foo::getBar);
Tuttavia, se si utilizza Optional.flatMap
, si otterrà un semplice Optional
; cioè Optional<Bar>
.
Optional<Bar> optionalBar =
Optional.of(new Foo())
.flatMap(Foo::getBar);