Mam metodę, która ma zwrócić obiekt, jeśli zostanie znaleziony.
Jeśli nie zostanie znaleziony, czy powinienem:
- zwróć null
- rzuć wyjątek
- inny
Mam metodę, która ma zwrócić obiekt, jeśli zostanie znaleziony.
Jeśli nie zostanie znaleziony, czy powinienem:
Odpowiedzi:
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.
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.
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.
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”.
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
find
i findOrFail
od Laravela Eloquenta
TryFindObject
metody? 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.
Chciałem tylko podsumować wspomniane wcześniej opcje, dodając kilka nowych:
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.
Expected<T> findObject(String)
gdzie Expected<T>
ma funkcje orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. To
Użyj wzorca obiektu zerowego lub wyrzuć wyjątek.
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.
Zalety rzucenia wyjątku:
Więcej wyjaśnień z przykładami można znaleźć na stronie: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
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 )
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.
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!
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ć.
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.
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
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.
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)) { ...
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()
}
...
Zasadniczo powinien zwracać null. Kod wywołujący metodę powinien zdecydować, czy zgłosić wyjątek, czy spróbować czegoś innego.
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.
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…
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.
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.
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.
Wyjątki powinny być wyjątkowe . Zwróć null, jeśli poprawne jest zwrócenie null .
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.
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.
null
. Aby uzyskać więcej informacji, zobacz najlepiej głosowaną odpowiedź.
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\"");
}
}
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:
W przeciwnym razie zwróć null.