Słyszałem głosy mówiące, że sprawdzanie zwróconej wartości null z metod jest złym projektem. Chciałbym poznać kilka powodów takiego stanu rzeczy.
pseudo kod:
variable x = object.method()
if (x is null) do something
oop
null
return-value
koen
źródło
źródło
Odpowiedzi:
Powodem, dla którego nie zwraca się wartości null, jest to, że nie trzeba go sprawdzać, a zatem kod nie musi podążać inną ścieżką w oparciu o zwracaną wartość. Możesz sprawdzić wzorzec obiektu zerowego, który zawiera więcej informacji na ten temat.
Na przykład, gdybym miał zdefiniować metodę w Javie, która zwraca Collection, zazwyczaj wolałbym zwrócić pustą kolekcję (tj.
Collections.emptyList()
) Zamiast null, ponieważ oznacza to, że mój kod klienta jest czystszy; na przykład... który jest czystszy niż:
źródło
null
jest „kontenerem”, który zawiera zero lub jeden wskaźnik do obiektów. (Z pewnością jest to wyraźnie modelowane przez HaskellaMaybe
w tych przypadkach i jest tym lepiej, gdy to robi.)Oto powód.
W Clean Code Roberta Martina pisze, że zwracanie wartości null jest złym projektem, gdy można zamiast tego zwrócić, powiedzmy, pustą tablicę. Skoro oczekiwanym wynikiem jest tablica, dlaczego nie? Umożliwi ci to iterację wyniku bez żadnych dodatkowych warunków. Jeśli jest to liczba całkowita, może wystarczy 0, jeśli jest to hash, pusty hash. itp.
Założeniem jest, aby nie zmuszać wywołującego kodu do natychmiastowego rozwiązywania problemów. Kod telefoniczny może nie chcieć się nimi przejmować. Dlatego też w wielu przypadkach wyjątki są lepsze niż zero.
źródło
Dobre zastosowania zwracania wartości null:
Złe zastosowania: próba zastąpienia lub ukrycia wyjątkowych sytuacji, takich jak:
W takich przypadkach zgłoszenie wyjątku jest bardziej odpowiednie, ponieważ:
Jednak wyjątków nie należy używać do obsługi normalnych warunków działania programu, takich jak:
źródło
boolean login(String,String)
wydaje się w porządku i tak jestAuthenticationContext createAuthContext(String,String) throws AuthenticationException
Tak, zwracanie wartości NULL to straszny projekt w świecie zorientowanym obiektowo. Krótko mówiąc, użycie NULL prowadzi do:
Sprawdź ten post na blogu, aby uzyskać szczegółowe wyjaśnienie: http://www.yegor256.com/2014/05/13/why-null-is-bad.html . Więcej w mojej książce Elegant Objects , Rozdział 4.1.
źródło
bool TryGetBlah(out blah)
LubFirstOrNull()
lubMatchOrFallback(T fallbackValue)
.isEmpty()
) I tylko wtedy, gdy jest prawdziwa, wywołaj metodę. Ludzie spierają się przeciwko drugiemu, twierdząc, że jest on gorszy - ale jak mówi Filozofia Unix, „cenisz czas ludzki ponad czas maszynowy” (tj. Trywialnie wolniejsza wydajność marnuje mniej czasu niż programiści debugujący kod, który daje fałszywe błędy).Kto powiedział, że to zły projekt?
Sprawdzanie wartości null jest powszechną praktyką, a nawet zalecaną, w przeciwnym razie wszędzie ryzykujesz NullReferenceExceptions. Lepiej jest obsługiwać błąd z wdziękiem niż rzucać wyjątki, gdy nie jest to konieczne.
źródło
Na podstawie tego, co powiedziałeś do tej pory, myślę, że nie ma wystarczających informacji.
Zwracanie wartości null z metody CreateWidget () wydaje się złe.
Zwracanie wartości null z metody FindFooInBar () wydaje się w porządku.
źródło
Create...
zwraca nową instancję lub zgłasza ;Get...
zwraca oczekiwaną istniejącą instancję lub zgłasza ;GetOrCreate...
zwraca istniejącą instancję lub nową instancję, jeśli żadna nie istnieje, lub zgłasza ;Find...
zwraca istniejące wystąpienie, jeśli istnieje, lubnull
. W przypadku zapytań dotyczących kolekcji -Get...
zawsze zwraca kolekcję, która jest pusta, jeśli nie znaleziono pasujących elementów.Jego wynalazca mówi, że to błąd wart miliardy dolarów!
źródło
To zależy od języka, którego używasz. Jeśli pracujesz w języku takim jak C #, w którym idiomatycznym sposobem wskazania braku wartości jest zwrócenie wartości null, to zwrócenie wartości null jest dobrym projektem, jeśli nie masz wartości. Alternatywnie, w językach takich jak Haskell, które idiomatycznie używają monady Może w tym przypadku, zwrócenie wartości null byłoby złym projektem (gdyby było to w ogóle możliwe).
źródło
null
w językach takich jak C # i Java są często przeciążone i mają pewne znaczenie w domenie. Jeśli sprawdzisznull
słowo kluczowe w specyfikacji języka, oznacza to po prostu „nieprawidłowy wskaźnik”. To prawdopodobnie nic nie oznacza w żadnej problematycznej domenie.null
czy „nie zainicjowana”null
Jeśli przeczytasz wszystkie odpowiedzi, stanie się jasne, że odpowiedź na to pytanie zależy od rodzaju metody.
Po pierwsze, gdy dzieje się coś wyjątkowego (IOproblem itp.), Logicznie wyjątki są generowane. Kiedy dokładnie coś jest wyjątkowe, to prawdopodobnie jest coś na inny temat.
Ilekroć metoda prawdopodobnie nie przyniesie żadnych wyników, istnieją dwie kategorie:
Puste enumrable, stringi itp. Są dobrymi przykładami
Jak wspomniano, zakłada się, że metoda prawdopodobnie nie daje wyniku, więc nie jest wyjątkowa, dlatego nie należy zgłaszać wyjątku. Wartość neutralna nie jest możliwa (na przykład: 0 nie jest szczególnie neutralnym wynikiem, w zależności od programu)
Dopóki nie mamy oficjalnego sposobu na oznaczenie, że funkcja może zwracać wartość null lub nie może, staram się zastosować konwencję nazewnictwa, aby to oznaczyć.
Podobnie jak w przypadku konwencji Try Something () dla metod, w przypadku których oczekuje się niepowodzenia, często nazywam moje metody Safe Something (), gdy metoda zwraca neutralny wynik zamiast null.
Nie jestem jeszcze w pełni w porządku z nazwą, ale nie mogłem wymyślić nic lepszego. Więc na razie z tym biegam.
źródło
Mam konwencję w tej dziedzinie, która dobrze mi służyła
W przypadku zapytań o pojedynczy przedmiot:
Create...
zwraca nową instancję lub zgłaszaGet...
zwraca oczekiwaną istniejącą instancję lub zgłaszaGetOrCreate...
zwraca istniejące wystąpienie lub nowe wystąpienie, jeśli żadne nie istnieje lub zgłaszaFind...
zwraca istniejące wystąpienie, jeśli istnieje, lubnull
W przypadku zapytań dotyczących kolekcji:
Get...
zawsze zwraca kolekcję, która jest pusta, jeśli nie znaleziono pasujących [1] elementów[1] z określonymi kryteriami, jawnymi lub niejawnymi, podanymi w nazwie funkcji lub jako parametry.
źródło
Get
gdy spodziewam się, że tam będzie, więc jeśli go nie ma, to jest błąd i wrzucam - nigdy nie muszę sprawdzać zwracanej wartości. Używam,Find
jeśli naprawdę nie wiem, czy tam jest, czy nie - wtedy muszę sprawdzić wartość zwracaną.Wyjątki dotyczą wyjątkowych okoliczności.
Jeśli celem funkcji jest znalezienie atrybutu skojarzonego z danym obiektem, a ten obiekt nie ma takiego atrybutu, może być właściwe zwrócenie wartości null. Jeśli obiekt nie istnieje, zgłoszenie wyjątku może być bardziej odpowiednie. Jeśli funkcja ma zwracać listę atrybutów, a nie ma żadnych do zwrócenia, zwrócenie pustej listy ma sens - zwracasz wszystkie atrybuty zerowe.
źródło
Można zwrócić wartość null, jeśli ma to jakieś znaczenie:
W takim przypadku sensowne jest zwrócenie wartości null, jeśli identyfikator nie odpowiada istniejącej encji, ponieważ pozwala to odróżnić przypadek, w którym nie znaleziono dopasowania, od uzasadnionego błędu.
Ludzie mogą pomyśleć, że jest to złe, ponieważ może być nadużywane jako „specjalna” wartość zwracana, która wskazuje stan błędu, co nie jest zbyt dobre, trochę jak zwracanie kodów błędów z funkcji, ale jest mylące, ponieważ użytkownik musi sprawdzić zwrot dla null, zamiast łapać odpowiednie wyjątki, np
źródło
Niekoniecznie jest to zły projekt - tak jak w przypadku wielu decyzji projektowych, to zależy.
Jeśli wynik metody jest czymś, co nie miałoby dobrego wyniku przy normalnym użyciu, zwrócenie wartości null jest w porządku:
Jeśli naprawdę zawsze powinien występować wynik inny niż zerowy, może być lepiej zgłosić wyjątek:
źródło
Optional<>
W niektórych scenariuszach chcesz zauważyć awarię, gdy tylko to nastąpi.
Sprawdzanie wartości NULL i nie potwierdzanie (w przypadku błędów programisty) lub zgłaszanie (w przypadku błędów użytkownika lub wywołującego) w przypadku niepowodzenia może oznaczać, że późniejsze awarie są trudniejsze do wyśledzenia, ponieważ nie znaleziono oryginalnego dziwnego przypadku.
Ponadto ignorowanie błędów może prowadzić do exploitów bezpieczeństwa. Być może brak wartości wynikał z faktu, że bufor został nadpisany lub tym podobne. Teraz nie ulegasz awarii, co oznacza, że exploiter ma szansę wykonać w Twoim kodzie.
źródło
Jakie widzisz alternatywy zwracania wartości null?
Widzę dwa przypadki:
W tym przypadku moglibyśmy: Zwrócić Null lub zgłosić (zaznaczony) wyjątek (lub może utworzyć element i zwrócić go)
W tym przypadku możemy zwrócić Null, zwrócić pustą listę lub zgłosić wyjątek.
Uważam, że zwrot null może być mniej dobry niż alternatywy, ponieważ wymaga od klienta, aby pamiętać o sprawdzeniu wartości null, zapomnieniu przez programistów i zakodowaniu
W Javie zgłoszenie sprawdzonego wyjątku RecordNotFoundException pozwala kompilatorowi przypomnieć klientowi o zajęciu się wielkością liter.
Uważam, że wyszukiwanie zwracające puste listy może być całkiem wygodne - po prostu zapełnij wyświetlacz całą zawartością listy, och, jest pusta, kod „po prostu działa”.
źródło
Czasami zwracanie wartości NULL jest właściwą rzeczą do zrobienia, ale szczególnie, gdy masz do czynienia z sekwencjami różnego rodzaju (tablice, listy, łańcuchy, co-masz-ty), prawdopodobnie lepiej jest zwrócić sekwencję o zerowej długości, ponieważ prowadzi do krótszego i, miejmy nadzieję, bardziej zrozumiałego kodu, nie zajmując się jednak dużo pisaniem po stronie implementującej API.
źródło
Spraw, aby wywoływały inną metodę po fakcie, aby dowiedzieć się, czy poprzednie wywołanie było puste. ;-) Hej, to wystarczyło dla JDBC
źródło
Podstawową ideą tego wątku jest programowanie defensywne. To znaczy kod przeciwko nieoczekiwanemu. Istnieje szereg różnych odpowiedzi:
Adamski sugeruje przyjrzenie się wzorcowi obiektów zerowych, przy czym ta odpowiedź została zatwierdzona i głosowała za tą sugestią.
Michael Valenty sugeruje również konwencję nazewnictwa, aby powiedzieć deweloperowi, czego można się spodziewać. ZeroConcept sugeruje prawidłowe użycie wyjątku, jeśli jest to powód NULL. I inni.
Jeśli ustalimy „zasadę”, że zawsze chcemy robić programowanie obronne, wtedy zobaczymy, że te sugestie są słuszne.
Ale mamy 2 scenariusze rozwoju.
Zajęcia „autorstwa” programisty: Autor
Klasy „zużyte” przez innego (być może) programistę: programistę
Niezależnie od tego, czy klasa zwraca wartość NULL dla metod zwracających wartość, czy nie, programista będzie musiał sprawdzić, czy obiekt jest prawidłowy.
Jeśli programista nie może tego zrobić, to ta klasa / metoda nie jest deterministyczna. Oznacza to, że jeśli „wywołanie metody” w celu pobrania obiektu nie robi tego, co „ogłasza” (np. GetEmployee), zrywa kontrakt.
Jako autor klasy zawsze chcę być uprzejmy i defensywny (i deterministyczny) podczas tworzenia metody.
Biorąc więc pod uwagę, że należy sprawdzić NULL lub NULL OBJECT (np. Jeśli (pracownik jako NullEmployee.ISVALID)) musi zostać sprawdzony i może się to zdarzyć w przypadku kolekcji pracowników, wówczas podejście zerowe jest lepszym podejściem.
Ale lubię też Michaela Valentego sugestia dotycząca nazwania metody, która MUSI zwrócić wartość null, np. GetEmployeeOrNull.
Autor, który zgłasza wyjątek, usuwa możliwość sprawdzenia poprawności obiektu przez dewelopera, co jest bardzo niekorzystne dla kolekcji obiektów i zmusza programistę do obsługi wyjątków podczas rozgałęziania używanego kodu.
Jako programista korzystający z klasy mam nadzieję, że autor da mi możliwość unikania lub programowania zerowej sytuacji, z którą mogą się spotkać ich klasy / metody.
Więc jako programista mógłbym programować defensywnie przed NULL z metody. Jeśli autor dał mi kontrakt, który zawsze zwraca obiekt (NULL OBJECT zawsze tak robi) i ten obiekt ma metodę / właściwość, za pomocą której można przetestować ważność obiektu, to użyłbym tej metody / właściwości, aby nadal używać obiektu , inaczej obiekt jest nieprawidłowy i nie mogę go użyć.
Podsumowując, autor klasy / metod musi zapewnić mechanizmy, które Programista może wykorzystać w swoim programowaniu obronnym. To znaczy jaśniejszy zamiar metody.
Deweloper powinien zawsze używać programowania obronnego do testowania poprawności obiektów zwróconych z innej klasy / metody.
pozdrowienia
GregJF
źródło
Inne opcje to: zwrócenie pewnej wartości, która wskazuje sukces lub nie (lub typ błędu), ale jeśli potrzebujesz tylko wartości logicznej, która wskaże sukces / niepowodzenie, zwracanie wartości zerowej w przypadku niepowodzenia, a obiekt wskazujący na sukces nie będzie być mniej poprawne, a następnie zwraca prawda / fałsz i pobiera obiekt za pomocą parametru.
Innym podejściem byłoby użycie wyjątku do wskazania awarii, ale tutaj - w rzeczywistości jest o wiele więcej głosów, które mówią, że jest to ZŁA praktyka (ponieważ używanie wyjątków może być wygodne, ale ma wiele wad).
Więc osobiście nie widzę nic złego w zwracaniu wartości null jako wskazaniu, że coś poszło nie tak, i sprawdzaniu tego później (aby faktycznie wiedzieć, czy ci się udało, czy nie). Ponadto ślepe myślenie, że twoja metoda nie zwróci wartości NULL, a następnie oprze na niej swój kod, może prowadzić do innych, czasem trudnych do znalezienia, błędów (chociaż w większości przypadków po prostu spowoduje to awarię systemu :), jak będziesz odnosić się do 0x00000000 prędzej czy później).
źródło
Null_function @wikipedia
źródło
Cóż, to na pewno zależy od celu metody ... Czasami lepszym wyborem byłoby rzucenie wyjątku. Wszystko zależy od przypadku.
źródło
Jeśli kod jest taki jak:
Jeśli masz fikcyjny obiekt, którego metoda execute () nic nie robi i zwracasz to zamiast Null w odpowiednich przypadkach, nie musisz sprawdzać przypadku Null i możesz zamiast tego zrobić:
Tak więc tutaj problem nie dotyczy sprawdzania wartości NULL i wyjątku, ale raczej polega na tym, że wywołujący musi inaczej (w jakikolwiek sposób) obsługiwać specjalne przypadki niezamierzone lub nie.
źródło
W moim przypadku musiałem zwrócić Map z metody, a następnie poszukać określonego klucza. Ale jeśli zwrócę pustą mapę, to doprowadzi to do NullPointerException i wtedy nie będzie to zupełnie inne zwracanie wartości null zamiast pustej mapy. Ale począwszy od Java8 mogliśmy używać Optional . To właśnie jest powodem wprowadzenia koncepcji opcjonalnej.
źródło
Dzień dobry,
Zwracanie wartości NULL, gdy nie można utworzyć nowego obiektu, jest standardową praktyką w wielu interfejsach API.
Dlaczego do diabła to zły projekt, nie mam pojęcia.
Edycja: Dotyczy to języków, w których nie ma wyjątków, takich jak C, gdzie jest to konwencja od wielu lat.
HTH
`` Avahappy,
źródło