Szukaj…


Wprowadzenie

Optional jest obiekt kontenerowy, który może zawierać lub nie zawierać wartości innej niż null. Jeśli wartość jest obecna, isPresent() zwróci true a get() zwróci wartość.

orElse() są dodatkowe metody, które zależą od obecności zawartej wartości, takie jak orElse() , która zwraca wartość domyślną, jeśli wartość nie jest obecna, oraz ifPresent() który wykonuje blok kodu, jeśli wartość jest obecna.

Składnia

  • Optional.empty () // Tworzy pustą instancję Opcjonalne.
  • Opcjonalne.of (wartość) // Zwraca Opcjonalne z określoną wartością inną niż null. Wyjątek NullPointerException zostanie zgłoszony, jeśli przekazana wartość ma wartość NULL.
  • Optional.ofNullable (wartość) // Zwraca wartość Opcjonalną z określoną wartością, która może być pusta.

Zwróć wartość domyślną, jeśli opcja jest pusta

Nie używaj po prostu Optional.get() ponieważ może to powodować NoSuchElementException . Metody Optional.orElse(T) i Optional.orElseGet(Supplier<? extends T>) zapewniają sposób podania wartości domyślnej w przypadku, gdy opcja jest pusta.

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

Zasadnicza różnica między orElse i orElseGet polega na tym, że ten drugi jest oceniany tylko wtedy, gdy opcja jest pusta, podczas gdy argument dostarczony do pierwszej jest oceniany, nawet jeśli opcja nie jest pusta. Dlatego orElse powinien być używany tylko dla stałych, a nigdy do dostarczania wartości w oparciu o jakiekolwiek obliczenia.

Mapa

Użyj metody map() Optional aby pracować z wartościami, które mogą być null bez wykonywania jawnych kontroli null :

(Należy zauważyć, że operacje map() i filter() są oceniane natychmiast, w przeciwieństwie do ich odpowiedników Stream, które są oceniane tylko podczas operacji terminalowej .)

Składnia:

public <U> Optional<U> map(Function<? super T,? extends U> mapper)

Przykłady kodu:

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"

Ponieważ Optional.map () zwraca pustą opcjonalną wartość, gdy funkcja mapowania zwraca null, możesz połączyć kilka operacji map () jako formę bezpiecznego odwoływania zer. Nazywa się to również łańcuchem zerowym .

Rozważ następujący przykład:

String value = foo.getBar().getBaz().toString();

Każde z getBar , getBaz i toString może potencjalnie NullPointerException .

Oto alternatywny sposób uzyskania wartości z metody toString() przy użyciu Optional :

String value = Optional.ofNullable(foo)
                       .map(Foo::getBar)
                       .map(Bar::getBaz)
                       .map(Baz::toString)
                       .orElse("");

Zwróci pusty ciąg, jeśli którakolwiek z funkcji mapowania zwróci wartość null.

Poniżej znajduje się inny przykład, ale nieco inny. Wyświetli wartość tylko wtedy, gdy żadna z funkcji mapowania nie zwróci wartości null.

Optional.ofNullable(foo)
        .map(Foo::getBar)
        .map(Bar::getBaz)
        .map(Baz::toString)
        .ifPresent(System.out::println);

Zgłaszaj wyjątek, jeśli nie ma wartości

Użyj metody orElseThrow() Optional aby uzyskać zawartą wartość lub orElseThrow() wyjątek, jeśli nie został ustawiony. Jest to podobne do wywoływania get() , z tym wyjątkiem, że pozwala na dowolne typy wyjątków. Metoda wymaga dostawcy, który musi zwrócić zgłoszony wyjątek.

W pierwszym przykładzie metoda po prostu zwraca zawartą wartość:

Optional optional = Optional.of("something");

return optional.orElseThrow(IllegalArgumentException::new);
// returns "something" string

W drugim przykładzie metoda zgłasza wyjątek, ponieważ nie ustawiono wartości:

Optional optional = Optional.empty();

return optional.orElseThrow(IllegalArgumentException::new);
// throws IllegalArgumentException

Możesz także użyć składni lambda, jeśli wymagane jest zgłoszenie wyjątku z komunikatem:

optional.orElseThrow(() -> new IllegalArgumentException("Illegal"));

Filtr

filter() służy do wskazania, że wartość ma być dostępna tylko wtedy, gdy pasuje do predykatu.

Pomyśl o tym tak, if (!somePredicate(x)) { x = null; } .

Przykłady kodu:

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

Używanie opcjonalnych kontenerów dla pierwotnych typów liczb

OptionalDouble , OptionalInt i OptionalLong działają podobnie jak Optional , ale są specjalnie zaprojektowane do zawijania typów pierwotnych:

OptionalInt presentInt = OptionalInt.of(value);
OptionalInt absentInt = OptionalInt.empty();

Ponieważ typy liczbowe mają wartość, nie ma specjalnej obsługi dla wartości null. Puste pojemniki można sprawdzić za pomocą:

presentInt.isPresent(); // Is true.
absentInt.isPresent(); // Is false.

Podobnie istnieją skróty ułatwiające zarządzanie wartością:

// 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();

Uruchom kod tylko wtedy, gdy istnieje wartość

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.

Leniwie podaj wartość domyślną za pomocą dostawcy

Normalna metoda orElse pobiera Object , więc możesz się zastanawiać, dlaczego istnieje tutaj opcja dostarczenia Supplier (metoda orElseGet ).

Rozważać:

String value = "something";
return Optional.ofNullable(value)
               .orElse(getValueThatIsHardToCalculate()); // returns "something"

Nadal wywoływałby getValueThatIsHardToCalculate() nawet jeśli jego wynik nie jest używany, ponieważ opcja nie jest pusta.

Aby uniknąć tej kary, dostarczasz dostawcę:

String value = "something";
return Optional.ofNullable(value)
               .orElseGet(() -> getValueThatIsHardToCalculate()); // returns "something"

W ten sposób getValueThatIsHardToCalculate() zostanie wywołana tylko wtedy, gdy Optional jest pusta.

FlatMap

flatMap jest podobny do map . Różnicę opisuje javadoc w następujący sposób:

Ta metoda jest podobna do map(Function) , ale pod warunkiem, odwzorowujący jest jeden, którego wynik jest już Optional , a jeżeli wywołany, flatMap nie zawinąć go z dodatkowym Optional .

Innymi słowy, podczas tworzenia łańcucha wywołania metody zwracającego wartość Optional użycie Optional.flatMap pozwala uniknąć tworzenia zagnieżdżonych Optionals .

Na przykład, biorąc pod uwagę następujące klasy:

public class Foo {
    Optional<Bar> getBar(){
        return Optional.of(new Bar());
    }
}

public class Bar {
}

Jeśli użyjesz Optional.map , otrzymasz zagnieżdżoną Optional ; tj. Optional<Optional<Bar>> .

Optional<Optional<Bar>> nestedOptionalBar =
    Optional.of(new Foo())
        .map(Foo::getBar);

Jeśli jednak użyjesz Optional.flatMap , otrzymasz prostą Optional ; tj. Optional<Bar> .

Optional<Bar> optionalBar =
    Optional.of(new Foo())
        .flatMap(Foo::getBar);


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow