Po co wyrzucać wyjątki?

Widziałem następujący kod wiele razy:

try
{
    ... // some code
}
catch (Exception ex)
{
    ... // Do something
    throw new CustomException(ex);

    // or
    // throw;

    // or
    // throw ex;
}
Czy możesz wyjaśnić cel ponownego rzucenia wyjątku? Czy jest to zgodne ze wzorem / najlepszą praktyką w obsłudze WYJĄTKÓW? (Czytałem gdzieś, że to się nazywa "informowanie rozmówcy" wzór?)
Author: Yaakov Ellis, 2008-09-22

13 answers

Zmiana tego samego wyjątku jest przydatna, jeśli chcesz, powiedzmy, zapisać wyjątek, ale nie obsłużyć go.

Rzucanie nowego wyjątku, który zawija złapany wyjątek jest dobre dla abstrakcji. na przykład Twoja biblioteka korzysta z biblioteki innej firmy, która wyświetla wyjątek, o którym klienci twojej Biblioteki nie powinni wiedzieć. W takim przypadku zawijasz go w typ wyjątku bardziej natywny dla twojej Biblioteki i rzucasz go zamiast tego.

 43
Author: Chris Jester-Young,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:15:12

Faktycznie istnieje różnica między

throw new CustomException(ex);

I

throw;

Drugi zachowa informacje o stosie.

Ale czasami chcesz, aby wyjątek był bardziej "przyjazny" dla Twojej domeny aplikacji, zamiast pozwolić, aby DatabaseException dotarł do twojego GUI, podnosisz swój niestandardowy wyjątek, który zawiera oryginalny wyjątek.

Na przykład:

try
{

}
catch (SqlException ex)
{
    switch  (ex.Number) {
        case 17:
        case 4060:
        case 18456:
           throw new InvalidDatabaseConnectionException("The database does not exists or cannot be reached using the supplied connection settings.", ex);
        case 547:
            throw new CouldNotDeleteException("There is a another object still using this object, therefore it cannot be deleted.", ex);
        default:
            throw new UnexpectedDatabaseErrorException("There was an unexpected error from the database.", ex);
    } 
}
 25
Author: Davy Landman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 08:15:32

Czasami chcesz ukryć szczegóły implementacji metody lub poprawić poziomu abstrakcji problemu, tak aby był on bardziej sensowny dla rozmówcy metody. Aby to zrobić, możesz przechwycić oryginalny wyjątek i zastąpić go Niestandardowy wyjątek, który lepiej nadaje się do wyjaśnienia problemu.

Weźmy na przykład metodę, która ładuje dane żądanego użytkownika z pliku tekstowego. Metoda zakłada, że istnieje plik tekstowy o nazwie ID użytkownika i przyrostku ".danych". Jeśli ten plik nie istnieje, nie ma większego sensu rzucanie wyjątku FileNotFoundException, ponieważ fakt, że dane każdego użytkownika są przechowywane w pliku tekstowym, jest szczegółem implementacji wewnątrz metody. Tak więc ta metoda mogłaby zamiast tego zawinąć oryginalny wyjątek w Niestandardowy wyjątek z Komunikatem wyjaśniającym.

W przeciwieństwie do wyświetlonego kodu, najlepszą praktyką jest zachowanie oryginalnego wyjątku poprzez wczytanie go jako właściwości InnerException twojego nowego wyjątek. Oznacza to, że deweloper może nadal analizować podstawowy problem, jeśli to konieczne.

Podczas tworzenia wyjątku niestandardowego, oto przydatna lista kontrolna:

• znajdź dobrą nazwę, która informuje, dlaczego wyjątek został wyrzucony i upewnij się, że nazwa kończy się słowem "wyjątek".

• upewnij się, że zaimplementowałeś trzy standardowe konstruktory WYJĄTKÓW.

• zaznacz wyjątek atrybutem Serializable.

• upewnij się, że zaimplementuj konstruktor deserializacji.

• Dodaj dowolne niestandardowe właściwości wyjątków, które mogą pomóc programistom lepiej zrozumieć i obsłużyć Twój wyjątek.

* jeśli dodasz dowolne właściwości niestandardowe, upewnij się, że zaimplementowałeś i nadpisałeś GetObjectData, aby serializować swoje właściwości niestandardowe.

* jeśli dodasz dowolne właściwości niestandardowe, Nadpisz właściwość Message, aby można było dodać swoje właściwości do standardowej wiadomości wyjątku.

• pamiętaj aby załączyć oryginalny wyjątek przy użyciu właściwości InnerException niestandardowego wyjątku.

 11
Author: HTTP 410,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:44:16

Zazwyczaj łapiesz i rzucasz ponownie z jednego z dwóch powodów, w zależności od tego, gdzie kod znajduje się architektonicznie w aplikacji.

W jądrze aplikacji zazwyczaj łapiesz i rzucasz ponownie, aby przetłumaczyć wyjątek na coś bardziej znaczącego. Na przykład, jeśli piszesz warstwę dostępu do danych i używasz niestandardowych kodów błędów w SQL Server, możesz przetłumaczyć SqlException na rzeczy takie jak ObjectNotFoundException. Jest to przydatne, ponieważ (a) ułatwia rozmówcom aby obsłużyć określone typy WYJĄTKÓW, oraz (b) ponieważ zapobiega to szczegółom implementacji tej warstwy, takim jak fakt, że używasz SQL Server do uporczywego wyciekania do innych warstw, co pozwala łatwiej zmieniać rzeczy w przyszłości.

Na granicach aplikacji często zdarza się łapać i ponownie rzucać bez tłumaczenia wyjątku, dzięki czemu można rejestrować jego szczegóły, pomagając w debugowaniu i diagnozowaniu problemów na żywo. Idealnie chcesz opublikować błąd gdzieś, że zespół operacyjny może łatwo monitorować (np. dziennik zdarzeń), jak również miejsce, które daje kontekst wokół miejsca, w którym wystąpił wyjątek w przepływie sterowania dla programistów (zazwyczaj śledzenie).

 9
Author: Greg Beech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:25:52

Myślę o następujących powodach:

  • Stałe utrzymywanie zestawu wyrzuconych typów wyjątków JAKO CZĘŚCI API, tak aby wywoływacze musieli się martwić tylko o stały zestaw WYJĄTKÓW. W Javie praktycznie jesteś do tego zmuszony, ze względu na mechanizm sprawdzonych WYJĄTKÓW.

  • Dodanie pewnych informacji kontekstowych do wyjątku. Na przykład, zamiast pozwolić, aby nagi "record not found" przeszedł z DB, możesz chcieć go złapać i dodać "... podczas przetwarzania zamówienia nr XXX, szukając produktu YYY".

  • Czyszczenie-zamykanie plików, cofanie transakcji, uwalnianie niektórych uchwytów.

 2
Author: Rafał Dowgird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:30:19

Ogólnie rzecz biorąc "zrób coś" polega albo na lepszym wyjaśnieniu wyjątku (na przykład zawijanie go w inny wyjątek), albo śledzeniu informacji za pośrednictwem określonego źródła.

Inną możliwością jest to, że typ wyjątku nie jest wystarczający, aby wiedzieć, czy wyjątek musi zostać złapany, w którym to przypadku wyłapanie go i zbadanie go dostarczy więcej informacji.

Nie oznacza to, że metoda jest używana z czysto dobrych powodów, wiele razy jest używana, gdy deweloper uważa, że śledzenie informacji może być potrzebne w pewnym momencie przyszłości, w którym to przypadku otrzymasz styl try {} catch {throw;}, który w ogóle nie jest pomocny.

 1
Author: Guvante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:15:13

Myślę, że to zależy od tego, co próbujesz zrobić z wyjątkiem.

Dobrym powodem byłoby najpierw zarejestrowanie błędu w catch, a następnie wrzucenie go do interfejsu użytkownika, aby wygenerować przyjazny komunikat o błędzie z opcją wyświetlenia bardziej "zaawansowanego / szczegółowego" widoku błędu, który zawiera oryginalny błąd.

Innym podejściem jest metoda "retry", np. liczba błędów jest przechowywana, a po pewnej liczbie powtórzeń jest to jedyny raz, gdy błąd jest wysyłany do stosu (to czasami robi się to dla dostępu do bazy danych dla wywołań bazy danych, które timeout, lub w dostępie do usług internetowych przez powolne sieci).

Będzie kilka innych powodów, aby to zrobić.

 1
Author: Jon Limjap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:15:14

Dla twojej wiadomości, jest to powiązane pytanie dotyczące każdego rodzaju ponownego rzutu: względy wydajności rzucania WYJĄTKÓW

Moje pytanie koncentruje się na "Dlaczego" ponownie rzucamy wyjątki i jego wykorzystanie w strategii obsługi wyjątków aplikacji.

 1
Author: tghoang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Dopóki nie zacząłem używać Entlib ExceptionBlock, używałem ich do rejestrowania błędów przed wyrzuceniem ich. Trochę paskudne, gdy myślisz, że mogłem sobie z nimi poradzić w tym momencie, ale w tym czasie lepiej było, aby zawiedli w UAT (po zalogowaniu), zamiast zakrywać błąd flow-on.

 0
Author: johnc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:13:00

Aplikacja najprawdopodobniej będzie łapać te ponownie wyrzucone wyjątki wyżej w stosie wywołań, a więc ponowne rzucanie ich pozwala temu wyższemu handlerowi przechwycić i przetworzyć je odpowiednio. Często zdarza się, że aplikacja posiada najwyższej klasy obsługę wyjątków, która rejestruje lub raportuje expections.

Inną alternatywą jest to, że koder był leniwy i zamiast łapać tylko zestaw WYJĄTKÓW, z którymi chcą się uporać, złapali wszystko, a następnie ponownie wyrzucili tylko z tymi, z którymi nie mogą sobie poradzić.

 0
Author: Phil Wright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:30:38

Jak wspomniał Rafał, czasami robi się to, aby przekonwertować wyjątek sprawdzony na wyjątek niezaznaczony lub na wyjątek sprawdzony, który jest bardziej odpowiedni dla API. Oto przykład:

Http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html

 0
Author: Deanna Gelbart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-30 16:52:44

Jeśli spojrzysz na wyjątki jako na alternatywny sposób uzyskania wyniku metody, to ponowne rzucenie wyjątku jest jak owinięcie wyniku w inny obiekt.

I jest to powszechna operacja w nie-wyjątkowym świecie. Zwykle dzieje się tak na granicy dwóch warstw aplikacji - gdy funkcja z warstwy B wywołuje funkcję z warstwy C, przekształca wynik C w wewnętrzną formę B.

A -- calls --> B -- calls --> C

Jeśli nie, to na layer A która wywołuje warstwę B będzie pełny zestaw WYJĄTKÓW JDK do obsługi. :-)

Jak również przyjęta odpowiedź wskazuje, layer A może nawet nie być świadomy wyjątku C.

Przykład

Layer a , servlet: pobiera obraz i meta informacje
warstwa B , biblioteka JPEG: zbiera dostępne tagi DCIM do analizy pliku JPEG
Layer C, a simple DB: A class reading string records from a losowy plik dostępu. Niektóre bajty są uszkodzone, więc rzuca wyjątek "nie można odczytać ciągu UTF-8 dla rekordu 'bibliographicCitation'".

Więc A nie zrozumie znaczenia ' bibliograficznegozobacz też Dlatego {[0] } powinien przetłumaczyć ten wyjątek dla A na TagsReadingException, który zawija oryginał.

 0
Author: Andrey Chaschev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 10:09:07

Głównym powodem ponownego wyrzucania wyjątków jest pozostawienie stosu wywołań nietkniętych, dzięki czemu można uzyskać pełniejszy obraz tego, co się dzieje i sekwencji wywołań.

 -3
Author: dimarzionist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 07:17:50