Java Language
Valfri
Sök…
Introduktion
Optional
är ett behållareobjekt som kan innehålla ett värde som inte är noll eller inte. Om ett värde är närvarande kommer isPresent()
att returnera true
och get()
kommer att returnera värdet.
Ytterligare metoder som beror på närvaron av det innehållande värdet tillhandahålls, till exempel orElse()
, som returnerar ett standardvärde om värdet inte finns, och ifPresent()
som kör ett kodblock om värdet är närvarande.
Syntax
- Optional.empty () // Skapar en tom valfri instans.
- Valfritt.of (värde) // Returnerar ett valfritt med det angivna icke-nullvärdet. En NullPointerException kastas om det överförda värdet är noll.
- Valfritt.ofNullable (värde) // Returnerar ett valfritt med det angivna värdet som kan vara noll.
Returnera standardvärdet om valfritt är tomt
Använd inte bara Optional.get()
eftersom det kan kasta NoSuchElementException
. Optional.orElse(T)
och Optional.orElseGet(Supplier<? extends T>)
ger ett sätt att tillhandahålla ett standardvärde om valfritt är tomt.
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
Den avgörande skillnaden mellan orElse
och orElseGet
är att den senare utvärderas endast när valfritt är tomt medan argumentet som tillhandahålls till det tidigare utvärderas även om valfritt inte är tomt. orElse
bör därför endast användas för konstanter och aldrig för att tillhandahålla värde baserat på någon slags beräkning.
Karta
Använd map()
-metoden för Optional
att arbeta med värden som kan vara null
utan att göra explicita null
:
(Observera att map()
och filter()
-operationerna utvärderas omedelbart, till skillnad från deras Stream-motsvarigheter som endast utvärderas vid en terminaloperation .)
Syntax:
public <U> Optional<U> map(Function<? super T,? extends U> mapper)
Kodexempel:
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"
Eftersom Optional.map () returnerar ett tomt valfritt när dess mappningsfunktion returnerar noll kan du kedja flera kart () -operationer som en form av noll-säker dereferencing. Detta kallas också Null-safe chaining .
Tänk på följande exempel:
String value = foo.getBar().getBaz().toString();
Vilket som helst av getBar
, getBaz
och toString
kan potentiellt kasta en NullPointerException
.
Här är ett alternativt sätt att få värdet från toString()
med Optional
:
String value = Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.orElse("");
Detta kommer att returnera en tom sträng om någon av mappningsfunktionerna returneras noll.
Nedan är ett annat exempel, men något annorlunda. Det kommer endast att skriva ut värdet om ingen av mappningsfunktionerna returnerade noll.
Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.ifPresent(System.out::println);
Kasta ett undantag om det inte finns något värde
Använd orElseThrow()
som Optional
att få det inneslutna värdet eller kasta ett undantag, om det inte har ställts in. Detta liknar att ringa get()
förutom att det tillåter godtyckliga undantagstyper. Metoden tar en leverantör som måste returnera det undantag som ska kastas.
I det första exemplet returnerar metoden helt enkelt det innehållande värdet:
Optional optional = Optional.of("something");
return optional.orElseThrow(IllegalArgumentException::new);
// returns "something" string
I det andra exemplet kastar metoden ett undantag eftersom ett värde inte har ställts in:
Optional optional = Optional.empty();
return optional.orElseThrow(IllegalArgumentException::new);
// throws IllegalArgumentException
Du kan också använda lambda-syntaxen om det krävs ett undantag med meddelande:
optional.orElseThrow(() -> new IllegalArgumentException("Illegal"));
Filtrera
filter()
används för att indikera att du bara vill ha värdet om det stämmer med ditt predikat.
Tänk på det som if (!somePredicate(x)) { x = null; }
.
Kodexempel:
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
Använda valfria behållare för primitiva numretyper
OptionalDouble
, OptionalInt
och OptionalLong
fungerar som Optional
, men är speciellt utformade för att linda in primitiva typer:
OptionalInt presentInt = OptionalInt.of(value);
OptionalInt absentInt = OptionalInt.empty();
Eftersom numeriska typer har ett värde finns det ingen speciell hantering för noll. Tomma behållare kan kontrolleras med:
presentInt.isPresent(); // Is true.
absentInt.isPresent(); // Is false.
På liknande sätt finns det kortheter för att stödja värdeförvaltning:
// 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();
Kör bara koden om det finns ett värde närvarande
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.
Lazily tillhandahåller ett standardvärde med en leverantör
Den normala orElse
metoden tar ett Object
, så du kanske undrar varför det finns ett alternativ att tillhandahålla en Supplier
här ( orElseGet
metoden).
Överväga:
String value = "something";
return Optional.ofNullable(value)
.orElse(getValueThatIsHardToCalculate()); // returns "something"
Det skulle fortfarande ringa getValueThatIsHardToCalculate()
även om resultatet inte används eftersom tillvalet inte är tomt.
För att undvika denna straff levererar du en leverantör:
String value = "something";
return Optional.ofNullable(value)
.orElseGet(() -> getValueThatIsHardToCalculate()); // returns "something"
Detta sätt getValueThatIsHardToCalculate()
kommer bara att ringas om Optional
är tomt.
FlatMap
flatMap
liknar map
. Skillnaden beskrivs av javadoc enligt följande:
Den här metoden liknar
map(Function)
, men den medföljande kartläggaren är en vars resultat redan är ettOptional
, och om det anropas,flatMap
inte flatMap det med ett extraOptional
.
Med andra ord, när du kedjan ett metodanrop att avkastningen ett Optional
, med hjälp av Optional.flatMap
undviker skapar kapslade Optionals
.
Till exempel, med följande klasser:
public class Foo {
Optional<Bar> getBar(){
return Optional.of(new Bar());
}
}
public class Bar {
}
Om du använder Optional.map
får du ett kapslat Optional
; dvs Optional<Optional<Bar>>
.
Optional<Optional<Bar>> nestedOptionalBar =
Optional.of(new Foo())
.map(Foo::getBar);
Men om du använder Optional.flatMap
får du ett enkelt Optional
; dvs Optional<Bar>
.
Optional<Bar> optionalBar =
Optional.of(new Foo())
.flatMap(Foo::getBar);