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ć
Optional
zamiastnull
- 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 Optional
s w kolekcjach, które są prawie tak złe jak null
s. Po prostu nie rób tego. ;)
Jeśli chodzi o twoje pytania
- Tak.
- Jeśli przeciążenie nie jest możliwe, tak.
- Jeśli inne podejścia (podklasowanie, dekorowanie, ...) nie są opcją, tak.
- Proszę nie!
Zalety
Wykonanie tego zmniejsza obecność null
s 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 Optional
wyraź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 Optional
znaczenia null
zdarzenia 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 null
oznacza obecność błędu. (Ponieważ jeśli pozwolono by na brakującą wartość, Optional
użyto by to). To sprawia, że debugowanie wyjątku wskaźnika zerowego jest o wiele łatwiejsze, ponieważ pytanie o znaczenie tego null
jest 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 Optional
s. W Javie 10 typy wartości mogą dodatkowo zmniejszyć lub usunąć karę.
Serializacja
Optional
nie 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”) .
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));