Zastosowania opcjonalne

271

Korzystam z Java 8 już od ponad 6 miesięcy, jestem całkiem zadowolony z nowych zmian API. Jednym z obszarów, w którym wciąż nie jestem pewny, jest czas użycia Optional. Wydaje mi się, że waham się między chęcią używania go wszędzie, gdzie coś może być null, i nigdzie.

Wydaje się, że jest wiele sytuacji, w których mógłbym go użyć i nigdy nie jestem pewien, czy to dodaje korzyści (czytelność / bezpieczeństwo zerowe), czy po prostu powoduje dodatkowe obciążenie.

Mam więc kilka przykładów i chciałbym zainteresować się przemyśleniami społeczności na temat tego, czy Optionaljest to korzystne.

1 - Jako typ zwracany przez metodę publiczną, gdy metoda może zwrócić null:

public Optional<Foo> findFoo(String id);

2 - Jako parametr metody, gdy parametr może być null:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - Jako opcjonalny członek fasoli:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - W Collections:

Ogólnie nie sądzę:

List<Optional<Foo>>

dodaje cokolwiek - zwłaszcza, że ​​można użyć filter()do usunięcia nullwartości itp., ale czy są jakieś dobre zastosowania Optionalw kolekcjach?

Jakieś przypadki, które przegapiłem?

Będzie
źródło
2
Jeden przypadek, który uważam za użyteczny, to na przykład jeśli masz mapę zastępczą. Na przykład Map<Character, String>. Jeśli nie ma podstawienie mogę użyć tego: Optional.ofNullable(map.get(c)).orElse(String.valueOf(c)). Pamiętaj też, że opcja została skradziona z Guawy i ma znacznie ładniejszą składnię:Optional.fromNullable(map.get(c)).or(String.valueOf(c));
fge
3
Również w kolekcjach są kolekcje, które nie dopuszczają wartości zerowych! Opcjonalnie pasuje tutaj rachunek. I możesz .filter(Optional::absent)
zerować
2
@fge Z całą uczciwością uważam, że koncepcja fakultatywna faktycznie wywodzi się z FP.
VH-NZZ
2
@fge nie jest lepiej wyrażone getOrDefault()?
Jim Garrison

Odpowiedzi:

206

Głównym celem Optionaljest zapewnienie środka dla funkcji zwracającej wartość wskazującą na brak wartości zwracanej. Zobacz tę dyskusję . Dzięki temu osoba dzwoniąca może kontynuować ciąg płynnych wywołań metod.

To najbardziej pasuje do przypadku nr 1 w pytaniu PO. Chociaż brak wartości jest bardziej precyzyjnym sformułowaniem niż zero, ponieważ coś takiego IntStream.findFirstnigdy nie może zwrócić wartości null.

W przypadku użycia # 2 , przekazując opcjonalny argument do metody, można sprawić, że zadziała, ale jest raczej niezdarny. Załóżmy, że masz metodę, która pobiera ciąg, po którym następuje opcjonalny drugi ciąg. Zaakceptowanie Optionaljako drugiego argumentu spowodowałoby kod w następujący sposób:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

Nawet zaakceptowanie wartości null jest przyjemniejsze:

foo("bar", "baz");
foo("bar", null);

Prawdopodobnie najlepiej jest mieć przeciążoną metodę, która akceptuje argument z jednym ciągiem i zapewnia domyślną wartość dla drugiego:

foo("bar", "baz");
foo("bar");

Ma to ograniczenia, ale jest o wiele ładniejsze niż którekolwiek z powyższych.

Przypadki użycia # 3 i # 4 , mające Optionalpole klasy lub strukturę danych, są uważane za niewłaściwe użycie interfejsu API. Po pierwsze, jest to sprzeczne z głównym celem projektowym, Optionaljak podano u góry. Po drugie, nie dodaje żadnej wartości.

Istnieją trzy sposoby radzenia sobie z brakiem wartości w zmiennej Optional: zapewnienie wartości zastępczej, wywołanie funkcji w celu podania wartości zastępczej lub zgłoszenie wyjątku. Jeśli przechowujesz dane w polu, możesz to zrobić podczas inicjalizacji lub przydziału. Jeśli dodajesz wartości do listy, jak wspomniano PO, możesz dodatkowo nie dodawać wartości, tym samym „spłaszczając” nieobecne wartości.

Jestem pewien, że ktoś może wymyślić jakieś wymyślone przypadki, w których naprawdę chce przechowywać Optionalw polu lub kolekcji, ale ogólnie najlepiej jest tego unikać.

Znaki Stuarta
źródło
46
Nie zgadzam się z punktem 3. Przydatne może być zastosowanie Optionaljako pola, gdy rzeczy mają być zrobione lub nie do wykonania w przypadku obecności lub braku wartości.
glglgl
15
Nie rozumiem, dlaczego robienie pracy if(foo == null)wewnętrznej byłoby lepsze niż przechowywanie pola jako optional. I nie rozumiem, dlaczego jawne dzwonienie getOptionalFoo()wewnętrzne jest lepsze niż przechowywanie pola jako Optional. Ponadto, jeśli jedno pole może być, nulla jedno pole nie może być null, dlaczego nie przekazać tego kompilatorowi, tworząc je Optionallub nie Optional.
mogronalol
27
@StuartMarks, to jedna z rzeczy, które mnie zaskakują, kiedy słyszę to od wszystkich Optional<>ekspertów: „nie przechowuj Optional<>w terenie”. Naprawdę staram się zrozumieć sens tego zalecenia. Rozważ drzewo DOM, w którym węzeł może mieć element nadrzędny lub nie. Wydaje się, że w przypadku użycia, Node.getParent()który powróci Optional<Node>. Czy naprawdę mam nullza każdym razem przechowywać i zawijać wynik? Czemu? Co kupuje mi ta dodatkowa nieefektywność poza tym, że mój kod wygląda brzydko?
Garret Wilson
7
@GarretWilson Z drugiej strony załóżmy, że masz Optional<Node> getParent() { return Optional.ofNullable(parent); }. To wygląda drogie, ponieważ przydziela Optionalza każdym razem! Ale jeśli dzwoniący rozpakuje go natychmiast, obiekt jest wyjątkowo krótkotrwały i nigdy nie jest promowany z otwartej przestrzeni. Może nawet zostać wyeliminowane przez analizę ucieczki JIT. Ostateczna odpowiedź brzmi „to zależy” jak zawsze, ale użycie Optionalw polach potencjalnie powoduje nadmierne zużycie pamięci i spowalnia przechodzenie przez strukturę danych. I wreszcie myślę, że to zaśmieca kod, ale to kwestia gustu.
Stuart Marks
6
@GarretWilson Więc napisałeś do tego bloga? Byłbym zainteresowany tym :)
akhil_mittal
78

Jestem spóźniony do gry, ale za to, co jest warte, chcę dodać moje 2 centy. Są sprzeczne z celem projektowymOptional , który dobrze podsumowuje odpowiedź Stuarta Marksa , ale nadal jestem przekonany o ich ważności (oczywiście).

Używaj opcjonalnie wszędzie

Ogólnie

Napisałem cały post na blogu o używaniu,Optional ale w zasadzie sprowadza się do tego:

  • zaprojektuj swoje klasy, aby w miarę możliwości unikać fakultatywności
  • we wszystkich pozostałych przypadkach domyślnie należy użyć Optionalzamiastnull
  • ewentualnie zrobić wyjątki dla:
    • zmienne lokalne
    • zwracają wartości i argumenty do metod prywatnych
    • bloki kodu krytyczne dla wydajności (bez zgadywania, użyj profilera)

Dwa pierwsze wyjątki mogą zmniejszyć postrzegany narzut zawijania i rozpakowywania odniesień w Optional. Są wybierane w taki sposób, że zero nie może legalnie przekroczyć granicy z jednej instancji do drugiej.

Zauważ, że prawie nigdy nie pozwoli to na Optionals w kolekcjach, które są prawie tak złe jak nulls. Po prostu nie rób tego. ;)

Jeśli chodzi o twoje pytania

  1. Tak.
  2. Jeśli przeciążenie nie jest możliwe, tak.
  3. Jeśli inne podejścia (podklasowanie, dekorowanie, ...) nie są opcją, tak.
  4. Proszę nie!

Zalety

Wykonanie tego zmniejsza obecność nulls w bazie kodu, chociaż ich nie eliminuje. Ale to nie jest nawet główny punkt. Istnieją inne ważne zalety:

Wyjaśnia zamiar

Użycie Optionalwyraźnie oznacza, że ​​zmienna jest, no cóż, opcjonalna. Każdy czytelnik twojego kodu lub konsument Twojego API zostanie pobity ponad to, że może tam nic nie być i że konieczne jest sprawdzenie przed uzyskaniem dostępu do wartości.

Usuwa niepewność

Bez Optionalznaczenia nullzdarzenia jest niejasne. Może to być prawna reprezentacja stanu (patrz Map.get) lub błąd implementacji, taki jak brakująca lub nieudana inicjalizacja.

Zmienia się to dramatycznie wraz z ciągłym używaniem Optional. Tutaj już występowanie nulloznacza obecność błędu. (Ponieważ jeśli pozwolono by na brakującą wartość, Optionalużyto by to). To sprawia, że ​​debugowanie wyjątku wskaźnika zerowego jest o wiele łatwiejsze, ponieważ pytanie o znaczenie tego nulljest już udzielone.

Więcej czeków zerowych

Teraz, gdy już nic nie może być null, można to egzekwować wszędzie. Niezależnie od tego, czy są to adnotacje, twierdzenia, czy zwykłe kontrole, nigdy nie musisz zastanawiać się, czy ten argument lub ten typ zwracany może być pusty. Nie może!

Niedogodności

Oczywiście nie ma srebrnej kuli ...

Występ

Zawijanie wartości (szczególnie prymitywów) w dodatkowej instancji może obniżyć wydajność. W ciasnych pętlach może to stać się zauważalne lub nawet gorsze.

Zauważ, że kompilator może być w stanie obejść dodatkowe odniesienie dla krótkich okresów życia Optionals. W Javie 10 typy wartości mogą dodatkowo zmniejszyć lub usunąć karę.

Serializacja

Optionalnie jest serializowalny, ale obejście nie jest zbyt skomplikowane.

Niezmienność

Ze względu na niezmienność typów ogólnych w Javie niektóre operacje stają się kłopotliwe, gdy rzeczywisty typ wartości jest wpychany do argumentu typu ogólnego. Podany jest tutaj przykład (patrz „Polimorfizm parametryczny”) .

Nicolai
źródło
Kolejną wadą (lub ograniczeniem) jest to, że nie można sortować wystąpień opcjonalnych (xxx), chociaż Oracle wyraźnie narzuciło to ograniczenie celowo. Sceptycznie podchodzę do zasadności udostępniania tych klas tam, gdzie powinny być one używane tylko w określonych okolicznościach, i zakładając, że programista zrobi to, co należy. Rozwiązanie jednego problemu może powodować inny. Może powinny istnieć ostrzeżenia kompilatora, aby pomóc programistom w korzystaniu z Opcjonalnych (xxx) klas w „niepożądany” sposób (np. Jako parametry metody, w kolekcjach, w konstruktorach itp.), Jeśli tak naprawdę nie jest to zamierzone użycie?
skomisa
Około 4, opcjonalne w kolekcjach: Czasami przydatne jest przechowywanie opcjonalnych w Lists. Dzieje się tak, gdy ważne jest, aby określony element znajdował się pod określonym indeksem, ale element może być obecny lub nie. Jest to wyraźnie określone przez List<Optional<T>>typ. Jeśli z drugiej strony ważne jest tylko, które obiekty, które są elementami niektórych kolekcji, nie ma sensu.
Lii
3
Myślę, że przypadek użycia nr 2 jest nadal bardzo wątpliwy. OptionalByły przekazywane do metody może być null. Co zyskałeś? Teraz musisz wykonać dwa czeki. Zobacz stackoverflow.com/a/31923042/650176
David V
2
@DavidV spójrz na listę korzyści, które dałem - wszystkie dotyczą również tej sprawy. Poza tym, jeśli pójdziesz all-in Optional(co powinno mieć miejsce, jeśli chcesz przekazać to jako argument), nullnigdy nie ma wartości prawnej. Wywołanie metody z jawnym parametrem nulljest oczywiście błędem.
Nicolai
28

Osobiście wolę korzystać z narzędzia IntelliJ Code Inspection Tool do używania @NotNulli @Nullablesprawdzania, ponieważ są to w dużej mierze czasy kompilacji (mogą mieć pewne kontrole w środowisku wykonawczym). Ma to niższe koszty ogólne w zakresie czytelności kodu i wydajności środowiska wykonawczego. Nie jest tak rygorystyczny, jak korzystanie z Opcjonalnego, jednak ten brak dyscypliny powinien być poparty przyzwoitymi testami jednostkowymi.

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

Działa to z Javą 5 i nie trzeba zawijać ani rozpakowywać wartości. (lub utwórz obiekty opakowania)

Peter Lawrey
źródło
7
Uhm, czy to adnotacje IDEA? Wolę @Nonnullosobiście JSR 305 - współpracuje z FindBugs;)
fge
@fge Brakuje standardów w tym zakresie, ale wierzę, że narzędzia są ogólnie konfigurowalne i nie musisz z tym skończyć@Nonnull @NotNull etc
Peter Lawrey
4
Tak, to prawda; POMYSŁ (13.x) daje trzy różne opcje ... Zawsze używam JSR 305 anywa
fge
3
Wiem, że to stare, ale dyskusja na temat adnotacji i narzędzi zasługuje na link do stackoverflow.com/questions/35892063/... - który w szczególności odnosi się do przypadku Java 8.
Stephan Herrmann
25

Myślę, że Guava Optional i ich strona wiki dość dobrze to ujmują:

Oprócz zwiększenia czytelności wynikającego z nadania zeru nazwy, największą zaletą Opcjonalnego jest jego idiotyczność. Zmusza Cię do aktywnego zastanowienia się nad nieobecną sprawą, jeśli chcesz, aby Twój program w ogóle się skompilował, ponieważ musisz aktywnie rozpakować Opcjonalne i rozwiązać tę sprawę. Null sprawia, że ​​niepokojąco łatwo jest po prostu zapomnieć o rzeczach i chociaż FindBugs pomaga, nie sądzimy, aby rozwiązało to problem równie dobrze.

Jest to szczególnie istotne, gdy zwracane są wartości, które mogą, ale nie muszą być „obecne”. Ty (i inni) znacznie bardziej prawdopodobne jest, że zapomnisz, że other.method (a, b) może zwrócić wartość zerową, niż możesz zapomnieć, że a może być zerowe, gdy implementujesz other.method. Zwrócenie Opcjonalne uniemożliwia dzwoniącym zapomnienie o tym przypadku, ponieważ muszą oni sam rozpakować obiekt, aby kod mógł się skompilować. - (Źródło: Guava Wiki - Używanie i unikanie null - Jaki jest sens? )

Optionaldodaje trochę narzutu, ale myślę, że jego wyraźną zaletą jest wyraźne stwierdzenie, że obiekt może być nieobecny i wymusza, aby programiści poradzili sobie z sytuacją. Zapobiega to, że ktoś zapomni ukochany != nullczek.

Biorąc przykład 2 , myślę, że pisanie kodu jest o wiele bardziej wyraźne:

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

niż

if(soundcard != null){
  System.out.println(soundcard);
}

Dla mnie Optionallepiej uchwycić fakt, że nie ma karty dźwiękowej.

Moje 2 ¢ o twoich punktach:

  1. public Optional<Foo> findFoo(String id);- Nie jestem tego pewien. Może zwrócę taki, Result<Foo>który może być pusty lub zawierać Foo. Jest to podobna koncepcja, ale nie bardzo Optional.
  2. public Foo doSomething(String id, Optional<Bar> barOptional);- Wolałbym @Nullable i sprawdzanie błędów, jak w odpowiedzi Petera Lawreya - patrz także ta dyskusja .
  3. Twój przykład książki - nie jestem pewien, czy użyłbym opcjonalnie wewnętrznie, co może zależeć od złożoności. W przypadku „interfejsu API” książki chciałbym Optional<Index> getIndex()wyraźnie wskazać, że książka może nie mieć indeksu.
  4. Nie używałbym tego w kolekcjach, raczej nie pozwalając na wartości zerowe w kolekcjach

Ogólnie starałbym się zminimalizować przekazywanie null. (Raz spalony ...) Myślę, że warto znaleźć odpowiednie abstrakty i wskazać innym programistom, co faktycznie reprezentuje pewna zwracana wartość.

Behe
źródło
15
Można by napisać soundcard.ifPresent(System.out::println). Wywołanie isPresentjest semantycznie takie samo jak sprawdzanie null.
lepszy oliwek
Problemem jest dla mnie to, że rzeczy z typami opcjonalnymi mogą nadal być puste. Aby być całkowicie bezpiecznym, musisz zrobić coś takiego if(soundcard != null && soundcard.isPresent()). Chociaż tworzenie interfejsu API, który zwraca Opcjonalne i może również zwracać wartość NULL, jest czymś, co mam nadzieję, że nikt nigdy tego nie zrobi.
Simon Baumgardt-Wellander
„Zmusza Cię do aktywnego zastanowienia się nad nieobecną sprawą, jeśli chcesz, aby Twój program w ogóle się skompilował, ponieważ musisz aktywnie rozpakować opcję Opcjonalną i rozwiązać tę sprawę”. Nie jestem do końca pewien, jak to wymusza, chociaż nie pracuję zbyt wiele w Javie. Czy możesz wyjaśnić, co robi Java, aby zmusić cię do rozpakowania ORAZ sprawdź, czy przypadek! IsPresent wystarczy po prostu skompilować?
zmiażdżyć
15

Z samouczka Oracle :

Opcjonalne nie ma na celu zastąpienia każdego odwołania zerowego w bazie kodu, ale raczej pomoc w projektowaniu lepszych interfejsów API, w których - po przeczytaniu sygnatury metody - użytkownicy mogą stwierdzić, czy należy oczekiwać wartości opcjonalnej. Ponadto opcja może zmusić cię do aktywnego rozpakowania opcji, aby poradzić sobie z brakiem wartości; w rezultacie chronisz swój kod przed niezamierzonymi wyjątkami wskaźnika zerowego.

Ctomek
źródło
3
Interfejsy API tylko dla części zwracanej metody, prawda? Opcjonalne nie powinny być używane jako parametry z powodu kasowania typu? czasami używam Opcjonalnie wewnętrznie w metodzie, przekonwertowanej z parametru zerowalnego lub jako inicjalizacji pola z parametru konstruktora zerowego ... wciąż próbuję dowiedzieć się, czy jest to bardziej użyteczne niż pozostawienie go jako pustego - ktoś ma jakieś przemyślenia?
ycomp
@ycomp Można znaleźć bardzo wiele informacji o tych przypadkach, w ten lub że pytanie. Odpowiedzi na te pytania mówią znacznie więcej niż o co pytano i obejmują inne sprawy. Aby uzyskać więcej informacji, przejrzyj więcej lub zadaj własne pytanie, ponieważ prawdopodobnie nie przyciągniesz tutaj dużej uwagi. ; )
ctomek
8

1 - Jako typ zwracany przez metodę publiczną, gdy metoda może zwrócić null:

Oto dobry artykuł, który pokazuje przydatność przypadku użycia nr 1. Tam jest ten kod

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            isocode = isocode.toUpperCase();
        }
    }
}
...

przekształca się w to

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

przez użycie Opcjonalnego jako wartości zwracanej odpowiednich metod pobierających .

artefex
źródło
2

Oto interesujące zastosowanie (wierzę) do ... Testów.

Zamierzam dokładnie przetestować jeden z moich projektów i dlatego buduję twierdzenia; tylko takie rzeczy muszę zweryfikować, a inne nie.

Dlatego tworzę rzeczy do potwierdzenia i używam aser do ich weryfikacji, w następujący sposób:

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

W klasie NodeAssert robię to:

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

Co oznacza, że ​​aser naprawdę uruchamia się tylko wtedy, gdy chcę sprawdzić etykietę!

fge
źródło
2

Optionalklasa pozwala uniknąć używania nulli stanowi lepszą alternatywę:

  • Zachęca to programistę do sprawdzania obecności w celu uniknięcia nieprzechwyconych NullPointerException.

  • Interfejs API staje się lepiej udokumentowany, ponieważ można zobaczyć, gdzie można oczekiwać wartości, które mogą być nieobecne.

Optionalzapewnia wygodny interfejs API do dalszej pracy z obiektem isPresent():; get(); orElse(); orElseGet(); orElseThrow(); map(); filter(); flatmap().

Ponadto wiele platform aktywnie korzysta z tego typu danych i zwraca je ze swojego interfejsu API.


źródło
2

W Javie nie używaj ich, chyba że jesteś uzależniony od programowania funkcjonalnego.

Nie mają one miejsca jako argumenty metody (przepraszam kogoś, że pewnego dnia przekaże ci wartość opcjonalną null, a nie tylko opcję pustą).

Mają sens dla zwracanych wartości, ale zachęcają klasę klienta do ciągłego rozciągania łańcucha budującego zachowanie.

FP i łańcuchy mają niewiele miejsca w imperatywnym języku, takim jak Java, ponieważ bardzo trudno jest debugować, a nie tylko czytać. Kiedy przechodzisz do linii, nie możesz poznać stanu ani intencji programu; musisz wkroczyć, aby to rozgryźć (w kodzie, który często nie jest twój, a wiele ramek stosu jest głębokich pomimo filtrów kroków) i musisz dodać wiele punktów przerwania w dół, aby upewnić się, że może się zatrzymać w dodanym kodzie / lambdzie, zamiast po prostu chodzić po trywialnych liniach if / else / call.

Jeśli chcesz programowania funkcjonalnego, wybierz coś innego niż Java i mam nadzieję, że masz narzędzia do debugowania.

user2023577
źródło
1

Nie sądzę, że Opcjonalny jest ogólnym substytutem metod, które potencjalnie zwracają wartości null.

Podstawowa idea: brak wartości nie oznacza, że ​​potencjalnie będzie ona dostępna w przyszłości. Jest to różnica między findById (-1) a findById (67).

Główną informacją Opcjonalnego dla dzwoniącego jest to, że może on nie liczyć na podaną wartość, ale może on być dostępny w pewnym momencie. Może zniknie ponownie i wróci później jeszcze raz. To jest jak włącznik / wyłącznik. Masz „opcję”, aby włączyć lub wyłączyć światło. Ale nie masz opcji, jeśli nie masz światła, aby włączyć.

Uważam więc, że zbyt niechlujne jest wprowadzanie Opcjonalnych wszędzie tam, gdzie potencjalnie wcześniej zwracano wartość NULL. Nadal będę używać wartości null, ale tylko w ograniczonych obszarach, takich jak korzeń drzewa, leniwa inicjalizacja i jawne metody find.

oopexpert
źródło
0

Wydaje Optionaljest przydatna tylko wtedy, gdy typ T w dowolnej to prymitywny typ jak int, long, char, itd. Dla „prawdziwych” klas, to nie ma sensu do mnie jak można użyć nullwartości tak.

Myślę, że zostało zaczerpnięte stąd (lub z innej podobnej koncepcji językowej).

Nullable<T>

W języku C # Nullable<T>zostało to wprowadzone dawno temu w celu zawijania typów wartości.

peter.petrov
źródło
2
Jest to Optionalw rzeczywistości
zdzierstwo Guawy
2
@fge OK, ale kiedy było to obecne w C # (2005, MS.NET 2.0), chyba nie było Guawy. I ... kto wie, skąd wziął to C #.
peter.petrov
3
@fge „Ripoff of Guava's Optional” to dość zabawny sposób, ponieważ faceci Guava uczestniczyli w dyskusjach, pod warunkiem, że ich doświadczenia i ogólnie byli za java.util.Optional.
Stuart Marks
6
@fge Bez wątpienia interfejsy API Javy były pod silnym wpływem Guava. Mam problem z „odrywaniem”, które brzmi jak kradzież. Faceci z Guawy wnieśli wiele cennych pomysłów do Javy 8.
Stuart Marks
6
Nie rozumiesz sedna sprawy. Opcjonalnie należy użyć zamiast zwracania wartości null. Jest to bezpieczniejsze niż potencjalne zgłoszenie wyjątku NullPointerException. Zobacz: oracle.com/technetwork/articles/java/…
Kilizo,
0

Ma podobne semantykę do niemodyfikowalne wystąpienie wzorca projektowego Iterator :Optional

  • może lub nie może odnosić się do obiektu (podanego przez isPresent())
  • można go wyrejestrować (za pomocą get()), jeśli odnosi się do obiektu
  • ale nie można przejść do następnej pozycji w sekwencji (nie ma next()metody).

Dlatego rozważ zwrócenie lub przekazanie Optionalw kontekstach, w których wcześniej mogłeś rozważyć użycie Javy Iterator.

Raedwald
źródło
-1

Java SE 8 wprowadza nową klasę o nazwie java.util.Optional,

Możesz utworzyć pustą opcję opcjonalną lub opcjonalną o wartości null.

Optional<String> emptyOptional = Optional.empty(); 

A oto Opcjonalne z wartością inną niż null:

String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );

Zrób coś, jeśli wartość jest obecna

Teraz, gdy masz obiekt opcjonalny, możesz uzyskać dostęp do dostępnych metod, aby jawnie poradzić sobie z obecnością lub brakiem wartości. Zamiast pamiętać o sprawdzeniu wartości zerowej, wykonaj następujące czynności:

String nullString = null;
if (nullString != null) {
    System.out.println(nullString);
}

Możesz użyć metody ifPresent () w następujący sposób:

Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);

package optinalTest;

import java.util.Optional;

public class OptionalTest {
    public Optional<String> getOptionalNullString() {
        return null;
//      return Optional.of("TESt");
    }

    public static void main(String[] args) {

        OptionalTest optionalTest = new OptionalTest();

        Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());

        if (optionalNullString.isPresent()) {
            System.out.println(optionalNullString.get());
        }
    }
}
Kumar Abhishek
źródło
ta copypaste miała na celu uzyskanie taniej reputacji, ale nie była związana z pytaniami OP
żądło