Przyczyną Optional
dodania do Java jest to, że:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
jest czystszy niż to:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
Chodzi mi o to, że Opcjonalne zostało napisane w celu obsługi programowania funkcjonalnego , które zostało dodane do Javy w tym samym czasie. (Przykład pochodzi z bloga Briana Goetza . Lepszym przykładem może być orElse()
metoda, ponieważ ten kod i tak wygeneruje wyjątek, ale otrzymujesz obraz.)
Ale teraz ludzie używają Opcjonalnego z zupełnie innego powodu. Używają go, aby naprawić lukę w projekcie języka. Wada jest taka: nie ma sposobu, aby określić, który z parametrów API i zwracane wartości mogą mieć wartość null. Może to być wspomniane w javadocs, ale większość programistów nawet nie pisze javadocs dla swojego kodu i niewielu sprawdzi javadocs podczas pisania. Prowadzi to do dużej ilości kodu, który zawsze sprawdza wartości zerowe przed ich użyciem, nawet jeśli często nie mogą być zerowe, ponieważ były już sprawdzane wielokrotnie dziewięć lub dziesięć razy w górę stosu wywołań.
Myślę, że było prawdziwe pragnienie rozwiązania tej wady, ponieważ tak wielu ludzi, którzy widzieli nową klasę Opcjonalną, przyjęło, że jej celem było zwiększenie przejrzystości interfejsów API. Dlatego ludzie zadają pytania typu „czy osoby pobierające powinny zwracać Opcjonalne?” Nie, prawdopodobnie nie powinny, chyba że spodziewasz się użycia gettera w programowaniu funkcjonalnym, co jest bardzo mało prawdopodobne. W rzeczywistości, jeśli spojrzysz na to, gdzie Opcjonalny jest używany w API Java, to głównie w klasach Stream, które są rdzeniem programowania funkcjonalnego. (Nie sprawdziłem bardzo dokładnie, ale klasy Stream mogą być jedynym miejscem, w którym są używane).
Jeśli planujesz używać modułu pobierającego w odrobinie kodu funkcjonalnego, dobrym pomysłem może być standardowy moduł pobierający i drugi, który zwraca Opcjonalne.
Aha, a jeśli chcesz, aby twoja klasa była serializowalna, absolutnie nie powinieneś używać Opcjonalnego.
Opcjonalne są bardzo złym rozwiązaniem wady API, ponieważ a) są bardzo gadatliwe, i b) nigdy nie miały na celu rozwiązania tego problemu.
O wiele lepszym rozwiązaniem usterki API jest moduł sprawdzania nieważności . Jest to procesor adnotacji, który pozwala określić, które parametry i zwracane wartości mogą być zerowe, poprzez opatrzenie ich adnotacją @Nullable. W ten sposób kompilator może zeskanować kod i dowiedzieć się, czy wartość, która może być równa null, jest przekazywana do wartości, w której null jest niedozwolony. Domyślnie zakłada się, że nic nie może mieć wartości null, chyba że jest to opatrzone adnotacjami. W ten sposób nie musisz się martwić o wartości zerowe. Przekazanie wartości zerowej do parametru spowoduje błąd kompilatora. Testowanie obiektu na wartość NULL, która nie może być NULL, powoduje wygenerowanie ostrzeżenia kompilatora. Efektem tego jest zmiana NullPointerException z błędu środowiska wykonawczego na błąd czasu kompilacji.
To zmienia wszystko.
Jeśli chodzi o osoby pobierające, nie używaj opcji opcjonalnej. I spróbuj zaprojektować swoje klasy, aby żaden z członków nie mógł być zerowy. I może spróbuj dodać Nullness Checker do swojego projektu i zadeklarować parametry pobierające i ustawiające @ Nullable, jeśli są potrzebne. Zrobiłem to tylko z nowymi projektami. Prawdopodobnie generuje wiele ostrzeżeń w istniejących projektach napisanych z mnóstwem zbędnych testów na wartość zerową, więc może być trudno go zmodernizować. Ale również złapie wiele błędów. Kocham to. Mój kod jest dzięki temu znacznie bardziej przejrzysty i bardziej niezawodny.
(Istnieje również nowy język, który rozwiązuje ten problem. Kotlin, który kompiluje się do kodu bajtu Java, pozwala określić, czy obiekt może być pusty, gdy go deklarujesz. To czystsze podejście.)
Dodatek do oryginalnego postu (wersja 2)
Po długim zastanowieniu niechętnie doszedłem do wniosku, że zwrot jest możliwy Opcjonalny pod jednym warunkiem: że odzyskana wartość może być zerowa. Widziałem dużo kodu, w którym ludzie rutynowo zwracają Opcjonalne od programów pobierających, które nie mogą zwrócić wartości null. Widzę to jako bardzo złą praktykę kodowania, która tylko zwiększa złożoność kodu, co zwiększa prawdopodobieństwo błędów. Ale gdy zwracana wartość może być równa null, śmiało zapakuj ją w Opcjonalne.
Należy pamiętać, że metody zaprojektowane do programowania funkcjonalnego i wymagające odwołania do funkcji będą (i powinny) zostać napisane w dwóch formach, z których jedna używa opcji opcjonalnej. Na przykład, Optional.map()
i Optional.flatMap()
oba odniesienia funkcyjne podjąć. Pierwsza odwołuje się do zwykłego gettera, a druga zwraca wartość Opcjonalną. Więc nie robisz nikomu przysługi, zwracając Opcjonalne, gdzie wartość nie może być zerowa.
Powiedziawszy to wszystko, nadal widzę, że podejście stosowane przez Kontroler Nullness jest najlepszym sposobem radzenia sobie z zerami, ponieważ zmieniają wyjątki NullPointerException od błędów środowiska wykonawczego w kompilowanie błędów czasu.