Czy powinienem zweryfikować wartość zwracaną wywołania metody, nawet jeśli wiem, że metoda nie może zwrócić złych danych wejściowych?

30

Zastanawiam się, czy powinienem bronić się przed wartością zwracaną wywołania metody, sprawdzając, czy spełniają one moje oczekiwania, nawet jeśli wiem, że metoda, którą wywołuję, spełni takie oczekiwania.

DANY

User getUser(Int id)
{
    User temp = new User(id);
    temp.setName("John");

    return temp;
}

CZY POWINNAM

void myMethod()
{
    User user = getUser(1234);
    System.out.println(user.getName());
}

LUB

void myMethod()
{
    User user = getUser(1234);

    // Validating
    Preconditions.checkNotNull(user, "User can not be null.");
    Preconditions.checkNotNull(user.getName(), "User's name can not be null.");

    System.out.println(user.getName());
}

Pytam o to na poziomie koncepcyjnym. Jeśli znam wewnętrzne działanie metody, którą wzywam. Albo dlatego, że to napisałem, albo sprawdziłem. A logika możliwych wartości, które zwraca, spełnia moje warunki wstępne. Czy „lepsze” lub „bardziej odpowiednie” jest pominięcie sprawdzania poprawności, czy powinienem nadal bronić się przed niewłaściwymi wartościami, zanim przejdę do metody, którą obecnie wdrażam, nawet jeśli zawsze powinna ona przejść.


Mój wniosek ze wszystkich odpowiedzi (nie wahaj się przyjść do swoich):

Podaj kiedy
  • W przeszłości metoda ta okazała się niewłaściwa
  • Metoda pochodzi z niezaufanego źródła
  • Metodę stosuje się z innych miejsc i nie określa ona wyraźnie warunków dodatkowych
Nie stwierdzaj, gdy:
  • Metoda żyje blisko Ciebie (szczegóły znajdziesz w wybranej odpowiedzi)
  • Metoda ta wyraźnie określa, że ​​jest to umowa z czymś takim, jak odpowiedni dokument, bezpieczeństwo typu, test jednostkowy lub kontrola po spełnieniu warunku
  • Wydajność ma kluczowe znaczenie (w takim przypadku aserowanie w trybie debugowania może działać jako podejście hybrydowe)
Didier A.
źródło
1
Celuj w to pokrycie 100% kodu!
Jared Burrows,
9
Dlaczego skupiasz się tylko na jednym problemie ( Null)? Prawdopodobnie jest to równie problematyczne, jeśli nazwa to ""(nie null, ale pusty ciąg) lub "N/A". Albo możesz zaufać wynikowi, albo musisz być odpowiednio paranoikiem.
MSalters
3
W naszej bazie kodu mamy schemat nazewnictwa: getFoo () obiecuje nie zwracać wartości null, a getFooIfPresent () może zwracać wartość null.
pjc50,
Skąd bierze się twoje domniemanie poczytalności kodu? Czy zakładasz, że wartość zawsze będzie różna od zera, ponieważ jest sprawdzana przy wprowadzaniu lub ze względu na strukturę, według której pobierana jest wartość? A co ważniejsze, czy testujesz każdy możliwy scenariusz przypadku krawędzi? W tym możliwość złośliwego skryptu?
Zibbobz

Odpowiedzi:

42

Zależy to od prawdopodobieństwa zmiany getUser i myMethod, a co ważniejsze, od prawdopodobieństwa zmiany niezależnie od siebie .

Jeśli w jakiś sposób wiesz na pewno, że getUser nigdy, nigdy, nigdy, nigdy się nie zmieni w przyszłości, to tak, to strata czasu na sprawdzanie poprawności, tak samo jak marnowanie czasu na sprawdzanie poprawności, która ima wartość 3 natychmiast po i = 3;instrukcji. W rzeczywistości tego nie wiesz. Ale są pewne rzeczy, które wiesz:

  • Czy te dwie funkcje „żyją razem”? Innymi słowy, czy mają te same osoby, które je utrzymują, czy są częścią tego samego pliku, a zatem czy prawdopodobnie same pozostaną „w synchronizacji”? W tym przypadku dodawanie kontroli sprawdzania poprawności jest prawdopodobnie przesadą, ponieważ oznacza to po prostu więcej kodu, który musi się zmienić (i potencjalnie spawnować błędy) za każdym razem, gdy obie funkcje zmienią się lub zostaną przekształcone w inną liczbę funkcji.

  • Czy funkcja getUser jest częścią udokumentowanego API z określoną umową, a myMethod jest jedynie klientem wspomnianego API w innej bazie kodu? Jeśli tak, możesz przeczytać tę dokumentację, aby dowiedzieć się, czy powinieneś sprawdzać poprawność zwracanych wartości (lub wstępnie sprawdzać parametry wejściowe!), Czy też naprawdę bezpiecznie jest ślepo podążać szczęśliwą ścieżką. Jeśli dokumentacja tego nie wyjaśnia, poproś opiekuna o naprawienie tego.

  • Wreszcie, jeśli ta konkretna funkcja nagle i nieoczekiwanie zmieniła swoje zachowanie w przeszłości, w sposób, który złamał kod, masz pełne prawo do paranoi. Błędy mają tendencję do skupiania się.

Pamiętaj, że wszystkie powyższe mają zastosowanie, nawet jeśli jesteś oryginalnym autorem obu funkcji. Nie wiemy, czy oczekuje się, że te dwie funkcje będą „żyć razem” przez resztę życia, czy będą powoli rozpadały się na osobne moduły, czy też jakoś postrzeliłeś się w stopę z błędem w starszym wieku wersje getUser. Ale pewnie można się domyślić.

Ixrec
źródło
2
Ponadto: jeśli miałbyś zmienić getUserpóźniej, aby mógł zwrócić null, czy jawne sprawdzenie dostarczyłoby ci informacji, których nie można uzyskać z „NullPointerException” i numeru wiersza?
user253751,
Wygląda na to, że można zweryfikować dwie rzeczy: (1) Metoda działa poprawnie, ponieważ nie zawiera błędów. (2) Metoda ta uwzględnia twoją umowę. Widzę sprawdzanie, czy numer 1 jest nadmierny. Zamiast tego powinieneś mieć testy wykonujące # 1. Dlatego nie sprawdziłbym poprawności i = 3 ;. Moje pytanie dotyczy więc # 2. Podoba mi się twoja odpowiedź, ale jednocześnie skorzystaj z odpowiedzi osądu. Czy widzisz jakiś inny problem wynikający z jawnego sprawdzania poprawności umów oprócz marnowania czasu na pisanie twierdzenia?
Didier A.
Jedynym innym „problemem” jest to, że jeśli twoja interpretacja umowy jest błędna lub staje się błędna, musisz zmienić całą weryfikację. Ale dotyczy to również wszystkich innych kodów.
Ixrec
1
Nie mogę iść przeciwko tłumowi. Ta odpowiedź jest zdecydowanie najbardziej poprawna w temacie mojego pytania. Chciałbym dodać, że po przeczytaniu wszystkich odpowiedzi, zwłaszcza @MikeNakis, myślę, że powinieneś teraz potwierdzić swoje warunki wstępne, przynajmniej w trybie debugowania, gdy masz jeden z dwóch ostatnich punktów Ixreca. Jeśli masz do czynienia z pierwszym punktem kuli, to zapewne przesada, aby potwierdzić swoje warunki wstępne. Wreszcie, biorąc pod uwagę wyraźną umowę, taką jak odpowiedni dokument, bezpieczeństwo typu, test jednostkowy lub sprawdzenie po spełnieniu warunków, nie powinieneś potwierdzać swoich warunków wstępnych, które byłyby przesadą.
Didier A.
22

Odpowiedź Ixreca jest dobra, ale przyjmuję inne podejście, ponieważ uważam, że warto to rozważyć. Na potrzeby tej dyskusji będę mówić o twierdzeniach, ponieważ jest to nazwa, pod którą Preconditions.checkNotNull()tradycyjnie znacie wasze .

Chciałbym zasugerować, że programiści często przeceniają stopień, w jakim są pewni, że coś zachowuje się w określony sposób, i nie doceniają konsekwencji takiego zachowania. Ponadto programiści często nie zdają sobie sprawy z mocy asercji jako dokumentacji. Z mojego doświadczenia wynika, że ​​programiści twierdzą o wiele rzadziej niż powinni.

Moim mottem jest:

Pytanie, na które powinieneś zawsze zadawać sobie pytanie, nie brzmi „czy powinienem to twierdzić?” ale „czy jest coś, o czym zapomniałem twierdzić?”

Oczywiście, jeśli jesteś absolutnie pewien, że coś zachowuje się w określony sposób, powstrzymasz się od stwierdzenia, że ​​tak właśnie się zachowało, i to w przeważającej części jest rozsądne. Naprawdę nie jest możliwe napisanie oprogramowania, jeśli nie możesz niczego zaufać.

Ale są wyjątki nawet od tej zasady. Co ciekawe, aby wziąć przykład z Ixreca, istnieje pewien rodzaj sytuacji, w której całkowicie pożądane jest podążanie int i = 3;za twierdzeniem, które irzeczywiście znajduje się w pewnym zakresie. Jest to sytuacja, w której imoże ulec zmianie ktoś, kto próbuje różnych scenariuszy „co, jeśli”, a poniższy kod opiera się na iposiadaniu wartości z określonego zakresu, i nie jest od razu oczywiste, szybko patrząc na poniższy kod, co dopuszczalny zakres to. int i = 3; assert i >= 0 && i < 5;Może więc z początku wydawać się bezsensowne, ale jeśli się nad tym zastanowić, to mówi ci, że możesz grać i, i określa zasięg, w którym musisz pozostać. Asercja jest najlepszym rodzajem dokumentacji, ponieważjest egzekwowane przez maszynę , więc jest doskonałą gwarancją, a wraz z kodem jest refaktoryzowane , więc pozostaje zawsze aktualne.

Twój getUser(int id)przykład nie jest bardzo odległym względnym krewnym assign-constant-and-assert-in-rangeprzykładu. Z definicji widzisz, że błędy zdarzają się, gdy rzeczy wykazują zachowanie inne niż oczekiwane. To prawda, że ​​nie możemy potwierdzić wszystkiego, więc czasami będzie trochę debugowania. Ale w branży jest dobrze ustalonym faktem, że im szybciej wykryjemy błąd, tym mniej go kosztuje. Pytania, które powinieneś zadać, to nie tylko to, czy masz pewność, że getUser()nigdy nie zwróci wartości zerowej (i nigdy nie zwróci użytkownika o pustej nazwie), ale także, jakie złe rzeczy będą się działo z resztą kodu, jeśli tak się stanie fakt, że pewnego dnia zwróci coś nieoczekiwanego i jak łatwo jest szybko spojrzeć na resztę kodu, aby dokładnie wiedzieć, czego się spodziewać getUser().

Jeśli nieoczekiwane zachowanie spowodowałoby uszkodzenie bazy danych, być może powinieneś to stwierdzić, nawet jeśli masz 101% pewności, że tak się nie stanie. Jeśli nullnazwa użytkownika spowodowałaby jakiś dziwny, tajemniczy, niewykrywalny błąd, tysiące linii w dół i miliardy cykli zegara później, być może najlepiej jest zawieść tak wcześnie, jak to możliwe.

Tak więc, chociaż nie zgadzam się z odpowiedzią Ixreca, sugeruję, abyście poważnie zastanowili się nad faktem, że twierdzenia nic nie kosztują, więc tak naprawdę nie ma nic do stracenia, tylko do zdobycia poprzez ich swobodne wykorzystanie.

Mike Nakis
źródło
2
Tak. Potwierdź to. Przyszedłem tutaj, aby dać mniej więcej tę odpowiedź. ++
RubberDuck
2
@ SteveJessop Poprawiłbym to ... && sureness < 1).
Mike Nakis,
2
@ MikeNakis: to zawsze koszmar podczas pisania testów jednostkowych, zwracana wartość, która jest dozwolona przez interfejs, ale niemożliwa do wygenerowania z jakichkolwiek danych wejściowych ;-) W każdym razie, gdy masz 101% pewności, że masz rację, to zdecydowanie się mylisz !
Steve Jessop
2
+1 za wskazanie rzeczy, o których całkowicie zapomniałem w swojej odpowiedzi.
Ixrec
1
@DavidZ To prawda, moje pytanie zakładało walidację w czasie wykonywania. Ale powiedzenie, że nie ufasz metodzie podczas debugowania i ufasz jej w prod, jest prawdopodobnie dobrym punktem widzenia na ten temat. Tak więc twierdzenie w stylu C może być dobrym sposobem radzenia sobie z tą sytuacją.
Didier A.
8

Zdecydowanie nie.

Dzwoniący nie powinien nigdy sprawdzać, czy funkcja, którą wywołuje, przestrzega jego umowy. Powód jest prosty: potencjalnie bardzo wielu dzwoniących i jest niepraktyczne, a prawdopodobnie nawet błędne z koncepcyjnego punktu widzenia dla każdego dzwoniącego, aby powielić logikę sprawdzania wyników innych funkcji.

Jeśli mają zostać wykonane jakiekolwiek kontrole, każda funkcja powinna sprawdzić swoje własne warunki końcowe. Warunki dodatkowe dają pewność, że funkcja została poprawnie zaimplementowana, a użytkownicy będą mogli polegać na umowie z tą funkcją.

Jeśli dana funkcja nie ma nigdy zwracać wartości null, należy to udokumentować i stać się częścią umowy tej funkcji. Właśnie o to chodzi w umowach: zaoferuj użytkownikom niezmienniki, na których mogą polegać, aby napotykali mniej przeszkód podczas pisania własnych funkcji.

Paweł
źródło
Zgadzam się z ogólnym sentymentem, ale istnieją okoliczności, w których zdecydowanie uzasadnia się walidacja wartości zwracanych. Na przykład, jeśli dzwonisz do zewnętrznej usługi sieci Web, czasami chcesz przynajmniej zweryfikować format odpowiedzi (xsd itp.)
AK_ 30.04.15
Wygląda na to, że opowiadasz się za stylem Design by Contract zamiast Defensing Programming. Myślę, że to świetna odpowiedź. Gdyby metoda miała ścisłą umowę, mógłbym jej zaufać. W moim przypadku tak nie jest, ale mógłbym to zmienić. Powiedz, że nie mogłem? Czy twierdzisz, że powinienem zaufać realizacji? Nawet jeśli nie stwierdza wprost w swoim dokumencie, że nie zwraca wartości null lub faktycznie ma sprawdzenie stanu końcowego?
Didier A.
Moim zdaniem, powinieneś wykorzystać swoją najlepszą ocenę i rozważyć różne aspekty, takie jak to, jak bardzo ufasz autorowi, że zrobi właściwą rzecz, jak prawdopodobne jest, że interfejs funkcji się zmieni i jak ścisłe są twoje ograniczenia czasowe. To powiedziawszy, przez większość czasu autor funkcji ma dość jasne pojęcie o tym, jaka powinna być umowa funkcji, nawet jeśli tego nie dokumentuje. Z tego powodu mówię, że powinieneś najpierw ufać autorom, że robią właściwą rzecz, i stać się defensywnym tylko wtedy, gdy wiesz, że funkcja nie jest dobrze napisana.
Paul,
Uważam, że najpierw ufanie innym, że robią dobrze, pomaga mi szybciej wykonać pracę. Biorąc to pod uwagę, rodzaje aplikacji, które piszę, można łatwo naprawić, gdy wystąpi problem. Ktoś pracujący z oprogramowaniem bardziej krytycznym dla bezpieczeństwa może pomyśleć, że jestem zbyt łagodny i wolę bardziej defensywne podejście.
Paul
5

Jeśli null jest prawidłową wartością zwracaną metody getUser, wówczas twój kod powinien obsłużyć to za pomocą If, a nie wyjątku - nie jest to wyjątkowy przypadek.

Jeśli null nie jest prawidłową wartością zwracaną metody getUser, oznacza to błąd w getUser - metoda getUser powinna zgłosić wyjątek lub w inny sposób zostać naprawiona.

Jeśli metoda getUser jest częścią biblioteki zewnętrznej lub w inny sposób nie można jej zmienić, a chcesz, aby wyjątki były zgłaszane w przypadku zwrotu zerowego, zapakuj klasę i metodę, aby wykonać kontrole i wyrzuć wyjątek, tak aby każde wystąpienie wywołanie getUser jest spójne w kodzie.

MatthewC
źródło
Null nie jest prawidłową wartością zwracaną przez getUser. Sprawdzając getUser, zauważyłem, że implementacja nigdy nie zwróci wartości null. Moje pytanie brzmi: czy powinienem zaufać mojej kontroli i nie mam kontroli w mojej metodzie, czy też wątpię w moją kontrolę i nadal mam czek. Możliwe jest również, że metoda zmieni się w przyszłości, przełamując moje oczekiwania, że ​​nie zwrócę wartości null.
Didier A.
A co, jeśli getUser lub user.getName zmienią się, aby zgłaszać wyjątki? Powinieneś mieć czek, ale nie jako część metody z wykorzystaniem Użytkownika. Zawiń metodę getUser - a nawet klasę użytkownika - aby wyegzekwować swoje umowy, jeśli martwisz się przyszłymi zmianami w łamaniu kodu getUser. Utwórz także testy jednostkowe, aby sprawdzić swoje założenia dotyczące zachowania klasy.
MatthewC
@didibus Aby sparafrazować swoją odpowiedź ... Emotikon uśmieszek nie jest prawidłową wartością zwrotną getUser. Sprawdzając getUser, zobaczyłem, że implementacja nigdy nie zwróci emotikonu . Moje pytanie brzmi: czy powinienem zaufać mojej kontroli i nie mam kontroli w mojej metodzie, czy też wątpię w moją kontrolę i nadal mam czek. Możliwe jest również, że metoda zmieni się w przyszłości, przełamując moje oczekiwania, że ​​nie będę zwracać emotikonów z uśmiechem . Dzwoniący nie musi potwierdzać, że wywoływana funkcja spełnia swoją umowę.
Vince O'Sullivan
@ VinceO'Sullivan Wygląda na to, że „umowa” jest w centrum problemu. I moje pytanie dotyczy umów niejawnych, a nie jednoznacznych. Metoda, która zwraca int Nie będę twierdzić, że nie otrzymuję łańcucha. Ale jeśli chcę tylko pozytywne ints, powinienem? Jest to tylko domniemane, że metoda nie zwraca ujemnego int, ponieważ go sprawdziłem. Z podpisu lub dokumentacji nie wynika jasno, że tak nie jest.
Didier A.
1
Nie ma znaczenia, czy umowa jest dorozumiana czy wyraźna. Sprawdzanie, czy wywoływana metoda zwraca prawidłowe dane po podaniu prawidłowych danych, nie jest zadaniem kodu wywołującego. W swoim przykładzie wiesz, że negatywne początki nie są niepoprawnymi odpowiedziami, ale czy wiesz, czy pozytywne int są poprawne? Ile testów naprawdę potrzebujesz, aby udowodnić, że metoda działa? Jedynym prawidłowym kursem jest założenie, że metoda jest poprawna.
Vince O'Sullivan
5

Argumentowałbym, że przesłanka twojego pytania jest wyłączona: po co używać zerowego odniesienia na początek?

Wzór zerowy obiekt jest sposobem, aby powrócić obiekty, które w zasadzie nic nie robić „Żaden użytkownik” zamiast wartości null zamian za użytkownika, zwraca obiekt, który reprezentuje

Ten użytkownik byłby nieaktywny, miałby pustą nazwę i inne niepuste wartości wskazujące „nic tutaj”. Podstawową korzyścią jest to, że nie trzeba zaśmiecać, ponieważ program zeruje kontrole, logowanie itp., Wystarczy użyć obiektów.

Dlaczego algorytm powinien dbać o wartość zerową? Kroki powinny być takie same. Równie łatwo i znacznie wyraźniej jest mieć obiekt zerowy, który zwraca zero, pusty ciąg znaków itp.

Oto przykład sprawdzania kodu dla wartości null:

User u = getUser();
String displayName = "";
if (u != null) {
  displayName = u.getName();
}
return displayName;

Oto przykład kodu używającego obiektu zerowego:

return getUser().getName();

Który jest jaśniejszy? Myślę, że drugi jest.


Chociaż pytanie jest oznaczone , warto zauważyć, że wzorzec zerowy jest naprawdę przydatny w C ++ podczas korzystania z referencji. Odwołania Java są bardziej podobne do wskaźników C ++ i pozwalają na null. Referencje w C ++ nie mogą być przechowywane nullptr. Jeśli ktoś chciałby mieć coś analogicznego do pustego odwołania w C ++, wzorzec zerowego obiektu jest jedynym sposobem, w jaki mogę to osiągnąć.

Społeczność
źródło
Null jest tylko przykładem tego, co twierdzę. Może być tak, że potrzebuję niepustego imienia. Moje pytanie nadal miałoby zastosowanie, czy potwierdziłbyś to? Lub może to być coś, co zwraca liczbę całkowitą, a ja nie mogę mieć wartości ujemnej lub musi znajdować się w danym zakresie. Nie myśl o tym jako o zerowym problemie na słowo.
Didier A.
1
Dlaczego metoda zwraca niepoprawną wartość? Jedyne miejsce, w którym należy to sprawdzić, znajduje się na granicy aplikacji: interfejsy z użytkownikiem i innymi systemami. W przeciwnym razie mamy wyjątki.
Wyobraź sobie, że miałem: int i = getCount; zmiennoprzecinkowa x = 100 / i; Jeśli wiem, że getCount nie zwraca 0, ponieważ albo napisałem metodę, albo ją sprawdziłem, czy powinienem pominąć sprawdzanie 0?
Didier A.
@didibus: możesz pominąć sprawdzenie, czy getCount() dokumentuje gwarancję, że nie zwraca teraz 0, i nie zrobi tego w przyszłości, z wyjątkiem sytuacji, gdy ktoś zdecyduje się dokonać przełomowej zmiany i chce zaktualizować wszystko, co wywołuje to, aby poradzić sobie z nowy interfejs. Zobaczenie, co robi obecnie kod, nie jest pomocne, ale jeśli zamierzasz sprawdzić kod, to kod do sprawdzenia to testy jednostkowe getCount(). Jeśli sprawdzą, czy nie zwraca 0, to wiesz, że jakakolwiek przyszła zmiana zwrotu 0 zostanie uznana za przełomową, ponieważ testy się nie powiodą.
Steve Jessop
Nie jest dla mnie jasne, że obiekty zerowe są lepsze niż wartości zerowe. Kaczka zerowa może kwakać, ale nie jest kaczką - w rzeczywistości semantycznie jest antytezą kaczki. Po wprowadzeniu obiektu zerowego każdy kod korzystający z tej klasy może być zmuszony sprawdzić, czy którykolwiek z jego obiektów jest obiektem zerowym - np. Masz w zbiorze coś pustego, ile masz rzeczy? To wydaje mi się sposobem na odroczenie niepowodzenia i zaciemnienie błędów. Linkowany artykuł wyraźnie ostrzega przed użyciem obiektów zerowych „tylko w celu uniknięcia kontroli zerowych i uczynienia kodu bardziej czytelnym”.
sdenham
1

Ogólnie rzecz biorąc, powiedziałbym, że zależy to głównie od następujących trzech aspektów:

  1. odporność: czy metoda wywołująca może poradzić sobie z nullwartością? Jeśli nullwartość może skutkować RuntimeExceptionpoleceniem sprawdzenia - chyba że złożoność jest niska i metody wywoływania / wywoływania są tworzone przez tego samego autora i nullnie są oczekiwane (np. Oba privatew tym samym pakiecie).

  2. odpowiedzialność za kod: jeśli programista A jest odpowiedzialny za getUser()metodę, a programista B korzysta z niej (np. jako część biblioteki), zdecydowanie zalecam sprawdzenie jej wartości. Tylko dlatego, że programista B może nie wiedzieć o zmianie, która powoduje potencjalną nullwartość zwrotu.

  3. złożoność: im wyższa ogólna złożoność programu lub środowiska, tym bardziej zalecam sprawdzenie wartości zwracanej. Nawet jeśli masz pewność, że nie może to być nulldzisiaj w kontekście metody wywoływania, być może będziesz musiał zmienić getUser()na inny przypadek użycia. Po kilku miesiącach lub latach i dodaniu kilku tysięcy linii kodów może to być pułapka.

Ponadto polecam udokumentować potencjalne nullzwracane wartości w komentarzu JavaDoc. Ze względu na wyróżnianie opisów JavaDoc w większości IDE, może to być pomocne ostrzeżenie dla każdego, kto używa getUser().

/** Returns ....
  * @param: id id of the user
  * @return: a User instance related to the id;
  *          null, if no user with identifier id exists
 **/
User getUser(Int id)
{
    ...
}
André
źródło
-1

Zdecydowanie nie musisz.

Na przykład, jeśli już wiesz, że zwrot nigdy nie może być zerowy - Dlaczego chcesz dodać czek zerowy? Dodanie czeku zerowego niczego nie zepsuje, ale jest po prostu zbędne. I lepiej nie kodować logiki redundantnej, o ile można tego uniknąć.

Yellen
źródło
1
Wiem, ale tylko dlatego, że sprawdziłem lub napisałem implementację drugiej metody. Umowa metody nie mówi wprost, że nie może. Może więc na przykład ulec zmianie w przyszłości. Lub może mieć błąd, który powoduje, że null zwraca, nawet jeśli próbuje tego nie robić.
Didier A.