Czy metoda pobierania powinna zwracać „null”, czy zgłaszać wyjątek, gdy nie może wygenerować wartości zwracanej? [Zamknięte]

503

Mam metodę, która ma zwrócić obiekt, jeśli zostanie znaleziony.

Jeśli nie zostanie znaleziony, czy powinienem:

  1. zwróć null
  2. rzuć wyjątek
  3. inny
Robert
źródło
57
Cokolwiek robisz, upewnij się, że to udokumentowałeś. Myślę, że ta kwestia jest ważniejsza niż dokładne podejście, które jest „najlepsze”.
Rik
6
Zależy to od dominujących idiomów języka programowania. Oznacz to pytanie tagiem języka programowania.
Teddy
3
Zwrócenie wartości null może oznaczać jedynie sukces lub porażkę, która bardzo często nie zawiera dużej ilości informacji (niektóre metody mogą zawieść na wiele sposobów). Biblioteki powinny lepiej zgłaszać wyjątki, aby błędy były wyraźne, w ten sposób główny program może zdecydować, jak obsłużyć błąd na wyższym poziomie (w przeciwieństwie do wbudowanej logiki obsługi błędów).
3k-
1
Wydaje mi się, że prawdziwym pytaniem jest to, czy powinniśmy uznać, że to wyjątkowe, by nie można było znaleźć bytu, a jeśli tak, to dlaczego? Nikt tak naprawdę nie odpowiedział wystarczająco, jak dojść do tego wniosku, a teraz pytania i odpowiedzi są zamknięte. Szkoda, że ​​branża nie osiągnęła konsensusu w tym ważnym temacie. Tak, wiem, że to zależy . Wyjaśnij więc, dlaczego to zależy bardziej niż „jeśli wyjątkowy, rzucaj”
zmiażdż

Odpowiedzi:

484

Jeśli zawsze oczekujesz znalezienia wartości, wyrzuć wyjątek, jeśli go brakuje. Wyjątek oznaczałby, że wystąpił problem.

Jeśli wartość może być brakująca lub obecna i obie są poprawne dla logiki aplikacji, zwróć wartość null.

Ważniejsze: co robisz w innych miejscach kodu? Spójność jest ważna.

Rozpoznać
źródło
30
@Ken: +1, fajnie byłoby wspomnieć, że jeśli rzucisz wyjątek, ale możesz go wykryć a priori (jak HasItem (...)), użytkownik powinien podać wspomnianą metodę Has * lub Contains.
user7116
4
Zamiast zwracać wartość lub null, gdy brakuje wartości, rozważ zwrócenie Może <T>. Zobacz mikehadlow.blogspot.nl/2011/01/monads-in-c-5-maybe.html .
Erwin Rooijakkers
2
W sposobie wyboru projektu @ErwinRooijakkers od wersji Java 8 można również zwrócić Opcjonalne <T>
José Andias
2
Uważam, że to trochę niepokojące, każda odpowiedź przypomina to samo przysłowie: „Jeśli jest wyjątkowy, rzuć”. Większość inżynierów zapozna się z tą zasadą. Moim zdaniem prawdziwe pytanie dotyczy tego, jak ustalić, czy należy to uznać za wyjątkowe. OP szuka najlepszej praktyki w odniesieniu do czegoś takiego jak na przykład wzór repozytorium. Czy zwykle uważa się za wyjątkowy, że obiekt nie istnieje, biorąc pod uwagę klucz podstawowy? Tak, to jest coś, co określi jego domena, ale co sugeruje większość ekspertów z wieloletnim doświadczeniem? Tego rodzaju odpowiedź powinniśmy zobaczyć.
zmiażdżyć
4
@crush Myślę, że główną zasadą jest to, jakie parametry są przekazywane do funkcji . Jeśli przekażesz tożsamość , tak jak wspominasz o kluczu podstawowym, należy uznać ją za wyjątkową, jeśli ten element nie zostanie znaleziony, ponieważ wskazuje na niespójny stan w systemie. Przykład: GetPersonById(25)wyrzuci, jeśli ta osoba zostanie usunięta, ale GetPeopleByHairColor("red")zwróci pusty wynik. Myślę więc, że parametry mówią coś o oczekiwaniach.
John Knoop
98

Zgłaszaj wyjątek tylko wtedy, gdy jest to naprawdę błąd. Jeśli oczekuje się, że obiekt nie będzie istniał, zwróć wartość null.

W przeciwnym razie jest to kwestia preferencji.

Carlton Jenke
źródło
4
Nie zgadzam się Możesz zgłaszać wyjątki jako kody statusu: „NotFoundException”
ACV
Z pewnością nie powinno to być kwestią preferencji. W ten sposób powstaje niespójny kod - jeśli nie jest to kod twojego zespołu, to prawie na pewno, gdy przeplatasz kod innego programisty z twoim własnym (biblioteki zewnętrzne).
zmiażdżyć
4
Myślę, że obsługa przypadku zerowego jest znacznie łatwiejsza niż „NotFoundException”. Zastanów się, ile linii wypróbowania musisz napisać wokół każdego żądania wycofania, które powoduje „NotFoundException” ... Bolesne jest przygotowanie całego tego kodu w moich oczach.
lep.
chciałbym zacytować Tony'ego Hoare'a: „Nazywam to moim błędem w wysokości miliarda dolarów”. Nie zwrócę wartości null, albo rzucę wyjątek i odpowiednio go obsłużę, albo zwrócę pusty obiekt.
siedem
70

Zgodnie z ogólną zasadą, jeśli metoda powinna zawsze zwracać obiekt, należy zastosować wyjątek. Jeśli spodziewasz się od czasu do czasu wartości zerowej i chcesz poradzić sobie z tym w określony sposób, wybierz wartość zerową.

Cokolwiek zrobisz, odradzam trzecią opcję: zwracanie ciągu „WTF”.

Matias Nino
źródło
Plus jeden, ponieważ w dawnych dobrych czasach robiłem to więcej niż kilka razy jako szybkie, brudne, „tymczasowe” rozwiązanie ... nie jest to dobry pomysł. Zwłaszcza jeśli zostanie to sprawdzone, jeśli jesteś studentem.
rciafardone
14
Chciałem obniżyć głosowanie, ponieważ opcje WTF wydawały mi się niesamowite ... ale najwyraźniej mam serce
swestner
5
wrzuć nowy WtfExcepti😲n
Kamafeather
Myślę, że byłoby pomocne, gdyby ta odpowiedź mówiła o powodach, dla których metoda zawsze zwraca obiekt w przeciwieństwie do „sporadycznego zerowania”. Co uzasadnia tego rodzaju sytuację? Podaj przykład, kiedy taka okoliczność może istnieć.
zmiażdżyć
51

Jeśli null nigdy nie wskazuje błędu, po prostu zwróć null.

Jeśli null jest zawsze błędem, wyrzuć wyjątek.

Jeśli wartość null jest czasem wyjątkiem, należy zakodować dwie procedury. Jedna procedura zgłasza wyjątek, a druga jest testem logicznym, który zwraca obiekt w parametrze wyjściowym, a procedura zwraca fałsz, jeśli obiekt nie został znaleziony.

Trudno jest niewłaściwie użyć procedury Try. Naprawdę łatwo zapomnieć o sprawdzeniu wartości null.

Więc kiedy null jest błędem, po prostu piszesz

object o = FindObject();

Gdy null nie jest błędem, możesz napisać coś takiego

if (TryFindObject(out object o)
  // Do something with o
else
  // o was not found
Kevin Gale
źródło
1
Byłaby to bardziej użyteczna sugestia, gdyby C # zapewniał prawdziwe krotki, abyśmy mogli uniknąć używania parametru [out]. Jest to jednak preferowany wzór, więc +1.
Erik Forbes,
2
Moim zdaniem podejście próbujące jest najlepsze. Nie musisz patrzeć w górę, co się stanie, jeśli obiekt nie będzie mógł zostać zwrócony. Dzięki metodzie Try od razu wiesz, co robić.
OregonGhost,
przypomina mi findi findOrFailod Laravela Eloquenta
vivoconunxino
@ErikForbes Wiem, że twój komentarz jest stary, ale czy odpowiedzią nie byłoby zdefiniowanie obiektu o wielu właściwościach, który zostałby zwrócony z TryFindObjectmetody? Krotki wydają się bardziej leniwym paradygmatem dla programistów, którzy nie chcą poświęcać czasu na definiowanie obiektu, który zawiera wiele wartości. To w zasadzie wszystkie krotki są w centrum.
zmiażdżyć
@crush - Nazwane literały Tuple są opcją IMO. To jest link do asynchronicznego wzorca Try Get Get z krotkami. stackoverflow.com/questions/1626597/…
ttugates
26

Chciałem tylko podsumować wspomniane wcześniej opcje, dodając kilka nowych:

  1. zwróć null
  2. rzuć wyjątek
  3. użyj wzorca obiektu zerowego
  4. podaj parametr boolowski dla twojej metody, aby osoba dzwoniąca mogła wybrać, czy chce zgłosić wyjątek
  5. podać dodatkowy parametr, aby osoba dzwoniąca mogła ustawić wartość, którą otrzymuje, jeśli nie zostanie znaleziona żadna wartość

Lub możesz połączyć te opcje:

Podaj kilka przeciążonych wersji programu pobierającego, aby osoba dzwoniąca mogła zdecydować, którą drogą wybrać. W większości przypadków tylko pierwszy ma implementację algorytmu wyszukiwania, a pozostałe tylko owijają się wokół pierwszego:

Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);

Nawet jeśli zdecydujesz się zapewnić tylko jedną implementację, możesz użyć takiej konwencji nazewnictwa, aby wyjaśnić umowę, a to pomoże ci, jeśli kiedykolwiek zdecydujesz się na dodanie innych implementacji.

Nie powinieneś go nadużywać, ale może to być pomocne, szczególnie przy pisaniu klasy pomocniczej, której będziesz używać w setkach różnych aplikacji z wieloma różnymi konwencjami obsługi błędów.

Lena Schimmel
źródło
Lubię jasne nazwy funkcji, szczególnie orCreate i orDefault.
marcovtwout
5
Większość z nich może być bardziej czysto napisane Expected<T> findObject(String)gdzie Expected<T>ma funkcje orNull(), orThrow(), orSupplied(Supplier<T> supplier), orDefault(T default). To
abstrakuje
Do tej pory nie wiedziałem o oczekiwanym <T>. Wydaje mi się, że jestem całkiem nowy i mógł nie istnieć, kiedy napisałem oryginalną odpowiedź. Może powinieneś zamienić swój komentarz w poprawną odpowiedź.
Lena Schimmel
Oczekiwany <T> to także szablon C ++. Czy istnieją również jego implementacje w innych językach obiektowych?
Lena Schimmel,
W Javie 8 zwracanie Opcjonalne <T> (w innych językach zwane Może <T> itp.) Jest również opcją. To wyraźnie wskazuje dzwoniącemu, że nic nie zwraca, i nie skompiluje się, jeśli dzwoniący nie skorzystał z tej możliwości, w przeciwieństwie do null, który (w każdym razie w Javie) skompiluje się, nawet jeśli dzwoniący nie sprawdzi .
Some Guy
18

Użyj wzorca obiektu zerowego lub wyrzuć wyjątek.

pmlarocque
źródło
To jest prawdziwa odpowiedź. Zwracanie wartości null jest strasznym nawykiem leniwych programistów.
jeremyjjbrown
Nie mogę uwierzyć, że ta odpowiedź nie została jeszcze wybrana na szczyt. To JEST prawdziwa odpowiedź, a każde z tych podejść jest wyjątkowo łatwe i pozwala zaoszczędzić sporo nadmiaru kodu lub błędów NPE.
Zmora
3
Jeśli użyjemy wzorca obiektu zerowego, jak odróżnić przypadek, w którym klucz jest odwzorowany na obiekt zerowy, od przypadku, w którym klucz nie ma odwzorowania? Sądzę, że zwrócenie bezsensownego obiektu byłoby znacznie gorsze niż zwrócenie wartości zerowej. Zwrócenie wartości NULL do kodu, który nie jest przygotowany do obsługi go, generalnie spowoduje zgłoszenie wyjątku. Nie jest to jednak optymalny wybór wyjątku, ale wyjątek. Zwrócenie nieistotnego obiektu powoduje, że kod niepoprawnie uznaje dane bez znaczenia za prawidłowe.
supercat
3
Jak zachowałby się obiekt zerowy dla wyszukiwania encji? Person somePerson = personRepository.find("does-not-exist");Załóżmy na przykład, że ta metoda zwraca obiekt zerowy dla identyfikatora does-not-exist. Do czego byłoby zatem właściwe zachowanie somePerson.getAge()? W tej chwili nie jestem jeszcze przekonany, że wzorzec obiektu zerowego jest właściwym rozwiązaniem dla wyszukiwania encji.
Abdull
13

Zachowaj spójność z używanymi interfejsami API.

dmckee
źródło
13

Zalety rzucenia wyjątku:

  1. Czystsza kontrola w kodzie telefonicznym. Sprawdzanie wartości null wstrzykuje gałąź warunkową, która jest natywnie obsługiwana przez try / catch. Sprawdzanie wartości null nie wskazuje tego, czego szukasz - czy sprawdzasz wartość null, ponieważ szukasz oczekiwanego błędu, czy sprawdzasz wartość null, aby nie przekazywać jej dalej w dół łańcucha ?
  2. Usuwa dwuznaczność tego, co oznacza „null”. Czy wartość null reprezentuje błąd lub czy wartość null jest faktycznie przechowywana w wartości? Trudno powiedzieć, kiedy masz tylko jedną rzecz, na której można oprzeć tę determinację.
  3. Poprawiona spójność między zachowaniem metody w aplikacji. Wyjątki są zwykle ujawniane w sygnaturach metod, dzięki czemu można lepiej zrozumieć, w jakich przypadkach krawędzi metody w koncie aplikacji i na jakie informacje aplikacja może zareagować w przewidywalny sposób.

Więcej wyjaśnień z przykładami można znaleźć na stronie: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

Clifford Oravec
źródło
2
+1, ponieważ punkt 2 jest doskonały - null nie ma takiego samego znaczenia jak nie znaleziono. Staje się to ważniejsze, gdy mamy do czynienia z dynamicznymi językami, w których Null może faktycznie być obiektem przechowywanym / pobieranym przez funkcję - i w takim przypadku
Adam Terrey
1
+1 za punkt # 2. Czy wartość null jest błędem? Czy null jest przechowywane dla danego klucza? Czy wartość null wskazuje, że klucz nie istnieje? To są prawdziwe pytania, które wyjaśniają, że zwracanie wartości null prawie nigdy nie jest poprawne. To prawdopodobnie najlepsza odpowiedź tutaj, ponieważ wszyscy inni właśnie rzucają niejednoznaczne „Jeśli to wyjątkowe, rzucaj”
zmiażdż
12

zależy to od tego, czy Twój język i kod promują: LBYL (spójrz przed skokiem) lub EAFP (łatwiej poprosić o wybaczenie niż pozwolenie)

LBYL mówi, że powinieneś sprawdzić wartości (więc zwróć null)
EAFP mówi, aby po prostu spróbować wykonać operację i sprawdzić, czy się nie powiedzie (wyrzuć wyjątek)

chociaż zgadzam się z powyższym .. wyjątki powinny być stosowane w wyjątkowych / błędnych warunkach, a zwracanie wartości null jest najlepsze w przypadku korzystania z czeków.


EAFP vs. LBYL w Pythonie:
http://mail.python.org/pipermail/python-list/2003-May/205182.html ( Archiwum sieciowe )

Corey Goldberg
źródło
3
W niektórych przypadkach EAFP jest jedynym sensownym podejściem. Na przykład w współbieżnej mapie / słowniku nie ma sposobu, aby zapytać, czy mapowanie będzie istniało, gdy będzie wymagane.
supercat
11

Po prostu zadaj sobie pytanie: „czy to wyjątkowy przypadek, że obiekt nie został znaleziony”? Jeśli oczekuje się, że nastąpi to w normalnym toku programu, prawdopodobnie nie powinieneś zgłaszać wyjątku (ponieważ nie jest to zachowanie wyjątkowe).

Wersja skrócona: użyj wyjątków, aby obsłużyć wyjątkowe zachowanie, a nie normalny przepływ kontroli w swoim programie.

-Alan.

AlanR
źródło
5

Wyjątki dotyczą projektowania według umowy.

Interfejs obiektów jest w rzeczywistości umową między dwoma obiektami, osoba dzwoniąca musi spełnić umowę, w przeciwnym razie odbiorca może po prostu zawieść z wyjątkiem. Istnieją dwie możliwe umowy

1) wszystkie dane wejściowe metoda jest poprawna, w takim przypadku musisz zwrócić null, gdy obiekt nie zostanie znaleziony.

2) tylko niektóre dane wejściowe są poprawne, tzn. Takie, które prowadzą do znalezienia obiektu. W takim przypadku MUSISZ zaoferować drugą metodę, która pozwoli dzwoniącemu ustalić, czy jego dane wejściowe będą prawidłowe. Na przykład

is_present(key)
find(key) throws Exception

JEŚLI i TYLKO JEŚLI podasz obie metody drugiej umowy, możesz zgłosić wyjątek, jeśli nic nie zostanie znalezione!

akuhn
źródło
4

Wolę po prostu zwrócić wartość zerową i polegać na dzwoniącym, aby odpowiednio go obsłużyć. Wyjątkiem (z powodu braku lepszego słowa) jest to, że jestem absolutnie „pewien”, że ta metoda zwróci obiekt. W takim przypadku awaria jest wyjątkową sprawą, którą powinien i powinien rzucić.

Swilliams
źródło
4

Zależy, co to znaczy, że obiekt nie został znaleziony.

Jeśli jest to normalny stan rzeczy, zwróć wartość null. To może się zdarzyć raz na jakiś czas, a dzwoniący powinni to sprawdzić.

Jeśli jest to błąd, a następnie wrzuć wyjątek, osoby dzwoniące powinny zdecydować, co zrobić z warunkiem błędu brakującego obiektu.

W końcu jedno z nich zadziałałoby, chociaż większość ludzi ogólnie uważa, że ​​dobrą praktyką jest stosowanie wyjątków tylko wtedy, gdy coś się wydarzyło.

Steve B.
źródło
2
Jak rozwinąłbyś stwierdzenie „ normalny stan rzeczy ” i jakich kryteriów użyjesz, aby rozróżnić je z błędem.
user1451111
4

Oto kilka innych sugestii.

Jeśli zwracasz kolekcję, unikaj zwracania wartości null, zwróć pustą kolekcję, która ułatwia wyliczanie bez uprzedniego sprawdzenia wartości null.

Kilka interfejsów API .NET używa wzorca parametru thrownOnError, który daje programowi wywołującemu wybór, czy jest to naprawdę wyjątkowa sytuacja, czy nie, jeśli obiekt nie zostanie znaleziony. Type.GetType jest tego przykładem. Innym częstym wzorcem w BCL jest wzorzec TryGet, w którym zwracana jest wartość logiczna, a wartość jest przekazywana przez parametr wyjściowy.

Możesz również wziąć pod uwagę wzorzec Null Object w niektórych okolicznościach, które mogą być domyślną lub wersją bez zachowania. Kluczem jest unikanie sprawdzania wartości zerowej w całej bazie kodu. Zobacz tutaj, aby uzyskać więcej informacji http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx

Duncan
źródło
3

W niektórych funkcjach dodaję parametr:

..., bool verify = true)

Prawda oznacza rzut, fałsz oznacza zwrócenie wartości zwracanej błędu. W ten sposób, kto korzysta z tej funkcji, ma obie opcje. Wartość domyślna powinna być prawdziwa, z korzyścią dla tych, którzy zapominają o obsłudze błędów.

Lew
źródło
3

Zwraca wartość null zamiast zgłaszania wyjątku i wyraźnie dokumentuje możliwość null wartości zwracanej w dokumentacji interfejsu API. Jeśli kod wywołujący nie honoruje interfejsu API i sprawdza, czy przypadek jest pusty, najprawdopodobniej i tak spowoduje to „wyjątek wskaźnika zerowego” :)

W C ++ mogę wymyślić 3 różne smaki konfiguracji metody, która znajdzie obiekt.

Opcja A

Object *findObject(Key &key);

Zwraca null, gdy nie można znaleźć obiektu. Ładne i proste. Poszedłbym z tym. Alternatywne podejścia poniżej są dla osób, które nie nienawidzą paramotów.

Opcja B

void findObject(Key &key, Object &found);

Przekaż odwołanie do zmiennej, która otrzyma obiekt. Metoda zgłosiła wyjątek, gdy nie można znaleźć obiektu. Ta konwencja jest prawdopodobnie bardziej odpowiednia, jeśli tak naprawdę nie oczekuje się, że obiekt nie zostanie znaleziony - dlatego zgłaszasz wyjątek, który oznacza, że ​​jest to nieoczekiwany przypadek.

Opcja C

bool findObject(Key &key, Object &found);

Metoda zwraca false, gdy nie można znaleźć obiektu. Zaletą tej opcji nad opcją A jest to, że można sprawdzić przypadek błędu w jednym wyraźnym kroku:

if (!findObject(myKey, myObj)) { ...
Ates Goral
źródło
3

odnosząc się tylko do przypadku, w którym null nie jest uważany za zachowanie wyjątkowe, zdecydowanie jestem za metodą wypróbowania, jasne jest, że nie trzeba „czytać książki” ani „patrzeć przed skokiem”, jak powiedziano tutaj

więc w zasadzie:

bool TryFindObject(RequestParam request, out ResponseParam response)

a to oznacza, że ​​kod użytkownika również będzie czysty

...
if(TryFindObject(request, out response)
{
  handleSuccess(response)
}
else
{
  handleFailure()
}
...
DorD
źródło
2

Jeśli ważne jest, aby kod klienta rozpoznał różnicę między znalezionym a nie odnalezionym, a ma to być rutynowe zachowanie, najlepiej zwrócić wartość null. Kod klienta może następnie zdecydować, co zrobić.

cokół
źródło
2

Zasadniczo powinien zwracać null. Kod wywołujący metodę powinien zdecydować, czy zgłosić wyjątek, czy spróbować czegoś innego.

Eran Galperin
źródło
2

Lub zwróć opcję

Opcją jest w zasadzie klasa kontenera, która zmusza klienta do obsługi skrzynek. Scala ma tę koncepcję, sprawdź, to API.

Następnie masz metody takie jak T getOrElse (T valueIfNull) na tym obiekcie, które albo zwracają znaleziony obiekt, albo alternatywną specyfikację klienta.

John Nilsson
źródło
2

Wolisz zwracać null -

Jeśli dzwoniący używa go bez sprawdzania, wyjątek zdarza się właśnie tam.

Jeśli dzwoniący tak naprawdę go nie używa, nie opodatkuj go try/ catchblok

kizzx2
źródło
2

Niestety JDK jest niespójny, jeśli próbujesz uzyskać dostęp do nieistniejącego klucza w pakiecie zasobów, nie znajdziesz wyjątku, a gdy poprosisz o wartość z mapy, otrzymasz wartość zerową, jeśli nie istnieje. Chciałbym więc zmienić odpowiedź zwycięzcy na następujące, jeśli znaleziona wartość może mieć wartość NULL, wówczas zgłaszaj wyjątek, gdy nie zostanie znaleziona, w przeciwnym razie zwróć NULL. Postępuj zgodnie z regułą z jednym wyjątkiem, jeśli chcesz wiedzieć, dlaczego nie znaleziono wartości, zawsze zgłaszaj wyjątek lub…

Dmitriy R.
źródło
1

Dopóki ma on zwracać odwołanie do obiektu, zwracanie wartości NULL powinno być dobre.

Jednak jeśli zwraca całą cholerną rzecz (jak w C ++, jeśli to zrobisz: „return bla;” zamiast „return & blah;” (lub „bla” to wskaźnik), to nie możesz zwrócić NULL, ponieważ jest to nie typu „obiekt”. W takim przypadku zgłoszenie wyjątku lub zwrócenie pustego obiektu, który nie ma ustawionej flagi sukcesu, jest sposobem, w jaki podejdę do problemu.

królikarnia
źródło
1

Nie sądzę, aby ktokolwiek wspominał o narzutach w obsłudze wyjątków - wymaga dodatkowych zasobów, aby załadować i przetworzyć wyjątek, więc chyba że jest to prawdziwe zdarzenie polegające na zabiciu aplikacji lub zatrzymaniu procesu (kontynuacja spowodowałaby więcej szkody niż pożytku), wybrałbym przekazanie wartość środowiska wywołującego może interpretować według własnego uznania.

ScottCher
źródło
1

Zgadzam się z tym, co wydaje się tutaj konsensusem (zwróć null, jeśli „nie znaleziono” jest normalnym możliwym wynikiem, lub wyrzuć wyjątek, jeśli semantyka sytuacji wymaga, aby obiekt zawsze był znaleziony).

Istnieje jednak trzecia możliwość, która może mieć sens w zależności od konkretnej sytuacji. Twoja metoda może zwrócić jakiś domyślny obiekt w stanie „nie znaleziono”, umożliwiając upewnienie się, że kod wywołujący zawsze otrzyma poprawny obiekt bez konieczności sprawdzania wartości NULL lub wychwytywania wyjątków.

GBegen
źródło
1

Zwróć wartość null, wyjątki są dokładnie takie: coś, co robi Twój kod, nie jest oczekiwane.

Anders
źródło
1

Jeśli metoda zwraca kolekcję, zwróć pustą kolekcję (jak powiedziano powyżej). Ale proszę nie Collect.EMPTY_LIST lub coś takiego! (w przypadku Java)

Jeśli metoda pobiera pojedynczy obiekt, masz kilka opcji.

  1. Jeśli metoda zawsze powinna znaleźć wynik i prawdziwym przypadkiem wyjątku jest nie znalezienie obiektu, należy zgłosić wyjątek (w Javie: proszę odznaczyć wyjątek)
  2. (Tylko Java) Jeśli możesz tolerować, że metoda zgłasza sprawdzony wyjątek, wyślij wyjątek ObjectNotFoundException lub podobny. W takim przypadku kompilator powie Ci, jeśli zapomnisz obsłużyć wyjątek. (To jest moja preferowana obsługa nie odnalezionych rzeczy w Javie.)
  3. Jeśli powiesz, że to naprawdę w porządku, jeśli obiekt nie zostanie znaleziony, a nazwa Twojej metody jest podobna do findBookForAuthorOrReturnNull (..), możesz zwrócić wartość null. W takim przypadku zdecydowanie zaleca się stosowanie kontroli statycznej lub kontroli kompilatora, która zapobiega dereferencjowaniu wyniku bez kontroli zerowej. W przypadku Javy może to być np. FindBugs (patrz DefaultAnnotation na stronie http://findbugs.sourceforge.net/manual/annotations.html ) lub IntelliJ-Checking.

Bądź ostrożny, jeśli zdecydujesz się zwrócić wartość zerową. Jeśli nie jesteś jedynym programistą w projekcie, otrzymasz NullPointerExceptions (w Javie lub cokolwiek w innych językach) w czasie wykonywania! Nie zwracaj więc wartości zerowych, które nie są sprawdzane podczas kompilacji.

iuzuz
źródło
Nie, jeśli kod został poprawnie napisany, aby się spodziewać null. Aby uzyskać więcej informacji, zobacz najlepiej głosowaną odpowiedź.
Andrew Barber
Ale tylko jeśli w czasie kompilacji upewnisz się, że wszystkie wartości null są sprawdzane. Można to zrobić za pomocą FindBugs @NutNull na poziomie pakietu i oznaczyć metodę jako „może zwrócić wartość null”. Lub użyć języka takiego jak Kotlin lub Nicea. Ale o wiele łatwiej jest nie zwracać wartości null.
iuzuz,
Może „Prostsze” . Ale często po prostu niepoprawne
Andrew Barber
1
Znowu: przeczytaj najczęściej głosowaną odpowiedź, aby uzyskać więcej informacji. Zasadniczo: jeśli potencjalnie oczekiwanym rezultatem jest to, że nie można znaleźć żądanej książki, wyjątek jest niewłaściwy , gdy żądanej książki nie można znaleźć, w przeciwieństwie do niektórych błędów.
Andrew Barber,
1
Dużo tu nie rozumiesz. Powszechnie stosujesz porady warunkowe, co prawie zawsze jest złym posunięciem. Przeczytaj także pozostałe głosowane odpowiedzi. Twoja odpowiedź zawiera tylko absolut i przedstawia wyjątkowo błędną logikę.
Andrew Barber,
1

Jeśli używasz biblioteki lub innej klasy, która zgłasza wyjątek, powinieneś go ponownie wyrzucić . Oto przykład. Example2.java jest jak biblioteka, a Example.java używa swojego obiektu. Main.java jest przykładem obsługi tego wyjątku. Powinieneś pokazać znaczącą wiadomość i (jeśli to konieczne) śledzenie stosu użytkownikowi po stronie wywołującej.

Main.java

public class Main {
public static void main(String[] args) {
    Example example = new Example();

    try {
        Example2 obj = example.doExample();

        if(obj == null){
            System.out.println("Hey object is null!");
        }
    } catch (Exception e) {
        System.out.println("Congratulations, you caught the exception!");
        System.out.println("Here is stack trace:");
        e.printStackTrace();
    }
}
}

Example.java

/**
 * Example.java
 * @author Seval
 * @date 10/22/2014
 */
public class Example {
    /**
     * Returns Example2 object
     * If there is no Example2 object, throws exception
     * 
     * @return obj Example2
     * @throws Exception
     */
    public Example2 doExample() throws Exception {
        try {
            // Get the object
            Example2 obj = new Example2();

            return obj;

        } catch (Exception e) {
            // Log the exception and rethrow
            // Log.logException(e);
            throw e;
        }

    }
}

Przykład2.java

 /**
 * Example2.java
 * @author Seval
 *
 */
public class Example2 {
    /**
     * Constructor of Example2
     * @throws Exception
     */
    public Example2() throws Exception{
        throw new Exception("Please set the \"obj\"");
    }

}
svlzx
źródło
Jeśli wyjątek, który ma zostać zgłoszony z funkcji, nie jest wyjątkiem środowiska wykonawczego, a program wywołujący powinien go obsłużyć (zamiast po prostu przerywać program), to zamiast zgłaszać wyjątek z wewnętrznego podsystemu, którego program wywołujący nie może oczekiwać, lepiej byłoby owinąć wyjątek wewnętrzny zewnętrznym sprawdzonym wyjątkiem, a jednocześnie „połączyć” wyjątek wewnętrzny, aby ktoś debugujący mógł dowiedzieć się, dlaczego został zgłoszony wyjątek zewnętrzny. Na przykład w przykładzie1 można użyć „rzuć nowy MyCheckedException („ Proszę ustawić \ ”obj \”, e) ”, aby uwzględnić„ e ”w zgłoszonym wyjątku.
Some Guy
0

To naprawdę zależy od tego, czy spodziewasz się znaleźć obiekt, czy nie. Jeśli podążasz za szkołą myślenia, że ​​do wskazania czegoś należy użyć wyjątków, no cóż, zdarzyło się coś wyjątkowego:

  • Obiekt znaleziony; zwróć obiekt
  • Obiekt nie znaleziony; wyrzucić wyjątek

W przeciwnym razie zwróć null.

Obrabować
źródło