Czy zwracanie wartości null jest złym projektem? [Zamknięte]

131

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
koen
źródło
13
Wyjaśnij: gdzie są ci ludzie, którzy mówią, że jest źle? Spinki do mankietów?
jcollum
2
Jeśli metoda jest czymś, nad czym masz kontrolę, możesz przeprowadzić testy jednostkowe, aby upewnić się, że nigdy nie zwróci wartości null, w przeciwnym razie nie rozumiem, dlaczego byłoby złą praktyką sprawdzanie, czy jest null, po tym wywołaniu; zwracanie wartości null może być złą praktyką, ale musisz chronić swój kod
BlackTigerX
9
Zgłaszanie wyjątków tylko dlatego, że nie ma danych do zwrócenia, jest niezwykle denerwujące. Normalny przepływ programu nie powinien zgłaszać wyjątków.
Thorarin
4
@David: Tak naprawdę powiedziałem. Jeśli metoda ma zwrócić dane, ale ich nie ma, oznacza to, że coś poszło nie tak. To nie jest normalny przebieg programu :)
Thorarin
2
@Thorarin: „normalny” przepływ programu to dość rozciągliwa koncepcja: nie jest to solidna podstawa do argumentacji.
Tomislav Nakic-Alfirevic

Odpowiedzi:

206

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

Collection<? extends Item> c = getItems(); // Will never return null.

for (Item item : c) { // Will not enter the loop if c is empty.
  // Process item.
}

... który jest czystszy niż:

Collection<? extends Item> c = getItems(); // Could potentially return null.

// Two possible code paths now so harder to test.
if (c != null) {
  for (Item item : c) {
    // Process item.
  }
}
Adamskiego
źródło
6
Tak, o wiele lepsze niż zwrócenie wartości zerowej i nadzieja, że ​​klient pamięta o załatwieniu sprawy.
djna
10
Z radością zgodzę się, że zwracanie wartości null jest szalone, gdy jest używane jako substytut pustych kontenerów (lub ciągów znaków). Nie jest to jednak powszechny przypadek.
MSalters
2
Dla mnie też +1 dla wzorca obiektu zerowego. Również gdy faktycznie chcę zwrócić wartość null, nadałem metodzie nazwę, taką jak getCustomerOrNull (), aby uczynić ją jawną. Myślę, że metoda jest dobrze nazwana, gdy czytelnik nie chce patrzeć na implementację.
Mike Valenty
4
Komentarz „// Dwie możliwe ścieżki kodu teraz” jest niepoprawny; masz dwie ścieżki kodu w obie strony. Jednak w przypadku zerowego obiektu Collection w pierwszym przykładzie ścieżka kodu „null” jest krótsza. Nadal masz jednak dwie ścieżki i nadal musisz przetestować dwie ścieżki.
Frerich Raabe
1
@MSalters - prawdopodobnie każda zmienna w językach OO nulljest „kontenerem”, który zawiera zero lub jeden wskaźnik do obiektów. (Z pewnością jest to wyraźnie modelowane przez Haskella Maybew tych przypadkach i jest tym lepiej, gdy to robi.)
Andrzej Doyle
71

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.

Max Chernyak
źródło
2
To jest wzorzec obiektu zerowego wspomniany w tej odpowiedzi: stackoverflow.com/questions/1274792/…
Scott Dorman
Pomysł polega na tym, że w przypadku błędu zwracasz pustą / pustą wersję dowolnego typu obiektu, który normalnie zwróciłbyś. Na przykład pusta tablica lub ciąg znaków będzie działać w takich przypadkach. Zwracanie „NULL” jest właściwe, gdy normalnie zwracasz wskaźnik (ponieważ NULL jest zasadniczo pustym wskaźnikiem). Zwracanie NULL w przypadku błędu z funkcji, która normalnie zwraca, powiedzmy, hash może być mylące. Niektóre języki radzą sobie z tym lepiej niż inne, ale generalnie spójność jest najlepszą praktyką.
bta
Niekoniecznie zwracasz błąd, chyba że błąd w jakiś sposób steruje przepływem (co nie jest dobrą praktyką) lub jest abstrakcyjny w API lub interfejsie. Błędy są po to, aby rozprzestrzeniać się na każdy poziom, na którym zdecydujesz się je złapać, dlatego nie musisz zajmować się nimi podczas wywoływania kontekstu. Są one domyślnie przyjazne dla wzorców obiektów null.
Max Chernyak
Niestety, wywołanie kodu nie zawsze uwzględnia przypadek pustej kolekcji (podobnie jak nie uwzględnia przypadku pustego). To może być problem, ale nie musi.
Sridhar Sarnobat
39

Dobre zastosowania zwracania wartości null:

  • Jeśli null jest prawidłowym wynikiem funkcjonalnym , na przykład: FindFirstObjectThatNeedsProcessing () może zwrócić wartość null, jeśli nie zostanie znaleziony, a wywołujący powinien odpowiednio sprawdzić.

Złe zastosowania: próba zastąpienia lub ukrycia wyjątkowych sytuacji, takich jak:

  • catch (...) and return null
  • Inicjalizacja zależności interfejsu API nie powiodła się
  • Brak miejsca na dysku
  • Nieprawidłowe parametry wejściowe (błąd programowania, dane wejściowe muszą zostać oczyszczone przez dzwoniącego)
  • itp

W takich przypadkach zgłoszenie wyjątku jest bardziej odpowiednie, ponieważ:

  • Zwracana wartość null nie zawiera żadnych znaczących informacji o błędzie
  • Bezpośredni rozmówca najprawdopodobniej nie może obsłużyć warunku błędu
  • Nie ma gwarancji, że dzwoniący sprawdza wyniki zerowe

Jednak wyjątków nie należy używać do obsługi normalnych warunków działania programu, takich jak:

  • Nieprawidłowa nazwa użytkownika / hasło (lub jakiekolwiek dane wprowadzone przez użytkownika)
  • Łamanie pętli lub jako nielokalne gotówki
ZeroConcept
źródło
7
Jednak „Nieprawidłowa nazwa użytkownika” wydaje się dobrym powodem do wyjątku.
Thilo
12
Użytkownicy wprowadzający niepoprawny login / hasło nie powinni być traktowani jako wyjątkowy stan, będący częścią normalnej pracy programu. Jednak brak odpowiedzi systemu uwierzytelniania (np. Active directory) jest stanem wyjątkowym.
ZeroConcept
2
Powiedziałbym, że to zależy: boolean login(String,String)wydaje się w porządku i tak jestAuthenticationContext createAuthContext(String,String) throws AuthenticationException
sfussenegger
1
W twoim przykładzie, jeśli nie ma pierwszego obiektu, który wymaga przetworzenia, istnieją dwa rozsądne sposoby rozwiązania tego przypadku. Pierwszy to wzorzec Null Object. Utwórz końcową podklasę, która reprezentuje nieistniejącą wersję klasy. Ma rozsądne wartości domyślne i zgłasza wyjątki, gdy żądane są bezsensowne działania. Inną techniką jest Option. To jest to, co jest dostępne w Javie8 i Scali. Każdy z nich pokazuje zamiary deweloperów. null nie może pokazać zamiaru, ponieważ ma zbyt wiele możliwych znaczeń. ** Pokazywanie intencji ** to najważniejszy aspekt kodu.
scott m gardner
29

Tak, zwracanie wartości NULL to straszny projekt w świecie zorientowanym obiektowo. Krótko mówiąc, użycie NULL prowadzi do:

  • obsługa błędów ad hoc (zamiast wyjątków)
  • niejednoznaczna semantyczna
  • powolny zamiast szybkiego awarii
  • myślenie komputerowe zamiast myślenia przedmiotowego
  • zmienne i niekompletne obiekty

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.

yegor256
źródło
2
Zdecydowanie się zgadzam. Nie podoba mi się nawet wzorzec obiektu zerowego, który wydaje się być taktyką opóźnienia „wybielania”. Albo twoja metoda ma zawsze odnosić sukcesy, albo nie. Jeśli zawsze się uda, rzuć. Jeśli może się nie powieść, zaprojektuj metodę tak, aby konsument wiedział, np. bool TryGetBlah(out blah)Lub FirstOrNull()lub MatchOrFallback(T fallbackValue).
Luke Puplett
Ja też nie lubię zwrotu null. Oddzielasz główną przyczynę od objawu, utrudniając debugowanie. Albo zgłoś wyjątek (szybko się nie powiedzie), albo wywołaj metodę sprawdzającą, która najpierw zwraca wartość logiczną (np. 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).
Sridhar Sarnobat,
22

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.

Brandon
źródło
11
+1. Zasmuca mnie kod, który rzuca wyjątki dla problemów, które można załagodzić na miejscu.
jkeys
6
Jak bardzo jesteś smutny, gdy programiści zapominają sprawdzić wartości null, a następnie uzyskują tajemnicze wyjątki od zerowych wskaźników? Sprawdzone wyjątki, w których kompilator przypomina użytkownikowi, że nie miał do czynienia z warunkami błędu, pozwalają uniknąć klas błędów kodowania.
djna
3
@djna: Myślę, że jest to również smutne, ale odkryłem, że ten sam typ koderów, którzy „zapominają” o sprawdzaniu wartości null, to ci, którzy w przypadku sprawdzonych wyjątków często je połykają.
Randy wspiera Monikę
5
Łatwiej jest wykryć obecność pustego bloku catch niż brak sprawdzenia zerowego.
Preston
21
@Preston: Zdecydowanie się nie zgadzam. Brak sprawdzenia zerowego można natychmiast zauważyć, kiedy się zawiesza. Połknięte wyjątki mogą przez lata rozprzestrzeniać tajemnicze i subtelne błędy ...
Beska
18

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.

jcollum
źródło
4
Podobnie jak w mojej konwencji: Zapytania o pojedynczy element - 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.
Johann Gerell
NULL jest zły z powodów podanych w yegor256 i odpowiedzi hakuinina, zwracanie poprawnego, ale pustego obiektu upraszcza
ogólne
12

Jego wynalazca mówi, że to błąd wart miliardy dolarów!

Bahadır Yağan
źródło
10

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).

Greg Beech
źródło
2
+1 za wzmiankę o monadzie. Uważam, że definicje nullw językach takich jak C # i Java są często przeciążone i mają pewne znaczenie w domenie. Jeśli sprawdzisz nullsłowo kluczowe w specyfikacji języka, oznacza to po prostu „nieprawidłowy wskaźnik”. To prawdopodobnie nic nie oznacza w żadnej problematycznej domenie.
MattDavey
Problem polega na tym, że nie wiesz, czy jest to „brakująca wartość”, nullczy „nie zainicjowana”null
CervEd
5

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:

  • Jeśli możliwe jest zwrócenie wartości neutralnej, zrób to .
    Puste enumrable, stringi itp. Są dobrymi przykładami
  • Jeśli taka neutralna wartość nie istnieje, należy zwrócić null .
    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.

Boris Callens
źródło
4

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łasza
  • Get...zwraca oczekiwaną istniejącą instancję lub zgłasza
  • GetOrCreate...zwraca istniejące wystąpienie lub nowe wystąpienie, jeśli żadne 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 [1] elementów

[1] z określonymi kryteriami, jawnymi lub niejawnymi, podanymi w nazwie funkcji lub jako parametry.

Johann Gerell
źródło
Dlaczego GetOne i FindOne zwracają się inaczej, jeśli nie zostały znalezione?
Vladimir Vukanac,
Opisałem różnicę. Używam, Getgdy 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, Findjeśli naprawdę nie wiem, czy tam jest, czy nie - wtedy muszę sprawdzić wartość zwracaną.
Johann Gerell,
3

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
1
Jeśli spróbujesz użyć atrybutu bez wartości, zasługuje na wyjątek. (Zakładam, że twoja specyfikacja mówi, że atrybut jest opcjonalny.) Miej oddzielną metodę, aby sprawdzić, czy jego wartość została ustawiona.
Preston
3

Można zwrócić wartość null, jeśli ma to jakieś znaczenie:

public String getEmployeeName(int id){ ..}

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

public Integer getId(...){
   try{ ... ; return id; }
   catch(Exception e){ return null;}
}
Steve B.
źródło
3
Tak. Jeśli masz warunek błędu, zgłoś wyjątek.
David Thornley
3
Jest to jeden przypadek, w którym wyjątek byłby uzasadniony. Jeśli pytasz o imię i nazwisko pracownika, który nie istnieje, coś jest nie tak.
Thorarin
Myślę, że to trochę dosłowne, Thorarinie - z pewnością możesz spierać się z moim przykładem, ale jestem pewien, że możesz sobie wyobrazić wystąpienie funkcji, która zwraca pasującą wartość lub null, jeśli nie ma dopasowania. A co powiesz na uzyskanie wartości z klucza w tablicy hashy? (powinienem był pomyśleć o tym przykładzie w pierwszej kolejności).
Steve B.
1
Tabela skrótów zwracająca wartość null dla klucza, który nie istnieje, jest zła. Robienie tego automatycznie oznacza, że ​​nie można przechowywać wartości null jako wartości bez niespójnego kodu.
RHSeeger
3

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:

object x = GetObjectFromCache();   // return null if it's not in the cache

Jeśli naprawdę zawsze powinien występować wynik inny niż zerowy, może być lepiej zgłosić wyjątek:

try {
   Controller c = GetController();    // the controller object is central to 
                                      //   the application. If we don't get one, 
                                      //   we're fubar

   // it's likely that it's OK to not have the try/catch since you won't 
   // be able to really handle the problem here
}
catch /* ... */ {
}
Michael Burr
źródło
2
Chociaż możesz natychmiast zarejestrować błąd diagnostyczny, a następnie może ponownie zgłosić wyjątek. Przechwytywanie danych w przypadku pierwszej awarii może być bardzo pomocne.
djna
Lub zawiń wyjątek w RuntimeException z informacjami diagnostycznymi w ciągu komunikatu. Zachowaj informacje razem.
Thorbjørn Ravn Andersen
Teraz (w 2018 roku) nie mogę się już zgodzić iw takich przypadkach powinniśmy sprzyjać powrotowiOptional<>
Piotr Müller
2

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.

Drew Hoskins
źródło
2

Jakie widzisz alternatywy zwracania wartości null?

Widzę dwa przypadki:

  • findAnItem (id). Co należy zrobić, jeśli element nie zostanie znaleziony

W tym przypadku moglibyśmy: Zwrócić Null lub zgłosić (zaznaczony) wyjątek (lub może utworzyć element i zwrócić go)

  • listItemsMatching (kryteria) co powinien zwrócić, jeśli nic nie zostanie znalezione?

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

x = find();
x.getField();  // bang null pointer exception

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”.

djna
źródło
3
Zgłaszanie wyjątków w celu wskazania warunku, który prawdopodobnie wystąpi podczas normalnego przepływu programu, prowadzi do naprawdę brzydkiego kodu, takiego jak try {x = find ()} catch (RecordNotFound e) {// do stuff}.
quant_dev
Zwracanie pustych list jest dobrym rozwiązaniem, ale tylko wtedy, gdy metoda znajduje się w kontekście, który może zwracać listy. W sytuacjach „findById” należy zwrócić wartość null. Nie lubię wyjątków RecordNotFound.
Thilo
To jest sedno naszej odmienności w opinii. Moim zdaniem nie ma dużej różnicy w pięknie między x = find (); if (x = null) {praca} else {rób rzeczy} i spróbuj złapać. W razie potrzeby jestem gotów poświęcić piękno dla poprawności kodu. Zbyt często w życiu napotykam kod, w którym zwracane wartości nie zostały sprawdzone.
djna
1

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.

Watyna
źródło
1

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

David Plumpton
źródło
1

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

GregJF
źródło
0

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).

Marcin Deptuła
źródło
0

Niezamierzone funkcje zerowe mogą pojawić się podczas tworzenia złożonych programów i podobnie jak martwy kod, takie zdarzenia wskazują na poważne wady struktur programu.

Funkcja lub metoda o wartości null jest często używana jako domyślne zachowanie funkcji z możliwością przywrócenia lub metody nadpisywalnej w strukturze obiektów.

Null_function @wikipedia

Juicy Scripter
źródło
0

Cóż, to na pewno zależy od celu metody ... Czasami lepszym wyborem byłoby rzucenie wyjątku. Wszystko zależy od przypadku.

Denis Biondic
źródło
0

Jeśli kod jest taki jak:

command = get_something_to_do()

if command:  # if not Null
    command.execute()

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ć:

get_something_to_do().execute()

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.

Zaraz
źródło
0

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.

Aman Gupta
źródło
-3

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,

Rob Wells
źródło
2
Jeśli nie możesz utworzyć obiektu, naprawdę powinieneś zgłosić wyjątek. Jeśli nie możesz znaleźć obiektu, który pasuje do jakiegoś zapytania, należy zwrócić wartość null.
Thilo
@Thilo, pokaż mi, jak to zrobić w C, a będę najbardziej zainteresowany.
Rob Wells
@RobWells C nie jest językiem zorientowanym obiektowo, ale to pytanie jest oznaczone jako „oop”
yegor256
@ yegor256 Masz rację. Brakowało mi oryginalnego tagu OOP. Ale, jak powiedział BS, klasa w C ++ jest po prostu strukturą z dodanymi kilkoma dodatkowymi funkcjami składowymi i pewnym wymyślnym zarządzaniem pamięcią działającym wewnętrznie. Ale jeśli API ma zwrócić strukturę, to zwracanie wartości NUL, gdy nie można utworzyć struktury, jest często konwencją.
Rob Wells