Kiedy rzucić wyjątek?

Mam wyjątki tworzone dla każdego warunku, którego moja aplikacja nie oczekuje. UserNameNotValidException, PasswordNotCorrectException itd.

Jednak powiedziano mi, że nie powinienem tworzyć wyjątków dla tych warunków. W moim UML są to wyjątki od głównego przepływu, więc dlaczego nie miałby to być wyjątek?

Jakieś wskazówki lub najlepsze praktyki tworzenia WYJĄTKÓW?

Author: Kwan Cheng, 2008-09-17

30 answers

Moje osobiste wytyczne są następujące: wyjątek jest wyrzucany, gdy podstawowe założenie bieżącego bloku kodu jest fałszywe.

Przykład 1: powiedzmy, że mam funkcję, która ma sprawdzać dowolną klasę i zwracać true, jeśli ta klasa dziedziczy z listy. Ta funkcja zadaje pytanie: "Czy ten obiekt jest potomkiem List?"Ta funkcja nigdy nie powinna rzucać wyjątku, ponieważ nie ma szarych obszarów w jej działaniu - Każda klasa albo dziedziczy, albo nie dziedziczy z listy, więc odpowiedź zawsze brzmi " tak " lub "nie".

Przykład 2: powiedzmy, że mam inną funkcję, która bada listę i zwraca true, jeśli jej długość jest większa niż 50, i false, jeśli długość jest mniejsza. Ta funkcja zadaje pytanie: "czy ta lista zawiera więcej niż 50 pozycji?"Ale to pytanie stawia założenie - zakłada, że dany obiekt jest listą. Jeśli przyznam mu NULL, to założenie jest fałszywe. W takim przypadku, jeśli funkcja zwraca albo true lub fałszywe, to łamie własne zasady. Funkcja nie może zwrócić niczego i twierdzić, że odpowiedziała poprawnie na pytanie. Więc nie wraca - rzuca wyjątek.

Jest to porównywalne do "ładowanego pytania" logicznego błędu. Każda funkcja zadaje pytanie. Jeśli podane dane wejściowe sprawiają, że to pytanie jest błędem, wyrzuć wyjątek. Linia ta jest trudniejsza do narysowania z funkcjami, które zwracają void, ale najważniejsze jest to, że jeśli założenia funkcji jeśli jego dane wejściowe są naruszane, powinien rzucić wyjątek zamiast zwracać normalnie.

Druga strona tego równania jest następująca: jeśli twoje funkcje często rzucają wyjątki, to prawdopodobnie musisz Dopracować ich założenia.

 548
Author: The Digital Gabeg,
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-11-06 21:55:18

Ponieważ są to rzeczy, które wydarzą się normalnie. Wyjątkami nie są mechanizmy przepływu sterowania. Użytkownicy często mylą hasła, nie jest to wyjątkowy przypadek. Wyjątki powinny być naprawdę rzadką rzeczą, UserHasDiedAtKeyboard sytuacje typu.

 275
Author: blowdart,
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
2015-07-19 11:24:39

Moje małe wytyczne są pod silnym wpływem Wielkiej książki "Code complete":

  • używaj WYJĄTKÓW do powiadamiania o rzeczach, których nie należy ignorować.
  • nie używaj WYJĄTKÓW, jeśli błąd może być obsługiwany lokalnie
  • Upewnij się, że wyjątki są na tym samym poziomie abstrakcji, co reszta rutyny.
  • wyjątki powinny być zarezerwowane dla tego, co naprawdę wyjątkowe .
 55
Author: Commander Keen,
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-19 18:43:08

Nie jest wyjątkiem, jeśli nazwa użytkownika nie jest poprawna lub hasło nie jest poprawne. To są rzeczy, których należy się spodziewać w normalnym przepływie pracy. Wyjątkami są rzeczy, które nie są częścią normalnego działania programu i są raczej rzadkie.

EDIT: nie lubię używać wyjątków, ponieważ nie można stwierdzić, czy metoda rzuca wyjątek po prostu patrząc na wywołanie. Dlatego wyjątki powinny być używane tylko wtedy, gdy nie możesz poradzić sobie z sytuacją w przyzwoity sposób (pomyśl " z pamięć" lub "komputer się pali").

 34
Author: EricSchaefer,
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-17 13:09:38

Jedną z zasad jest używanie WYJĄTKÓW w przypadku czegoś, czego normalnie nie można przewidzieć. Przykładami są łączność z bazą danych, brakujący plik na dysku itp. W przypadku scenariuszy, które można przewidzieć, czyli użytkowników próbujących zalogować się za pomocą złego hasła, należy używać funkcji, które zwracają wartości logiczne i wiedzą, jak poradzić sobie z sytuacją z wdziękiem. Nie chcesz nagle zakończyć wykonania, rzucając wyjątek tylko dlatego, że ktoś źle wpisał swoje hasło.

 24
Author: japollock,
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-16 21:13:19

Inni sugerują, że wyjątki nie powinny być używane, ponieważ błędnego Logowania należy się spodziewać w normalnym przepływie, jeśli użytkownik błędnie wpisuje. Nie zgadzam się i nie rozumiem rozumowania. Porównaj to z otwarciem pliku.. jeśli plik nie istnieje lub z jakiegoś powodu nie jest dostępny, to framework wyrzuci wyjątek. Użycie powyższej logiki było błędem Microsoftu. Powinni byli zwrócić kod błędu. To samo dotyczy parsowania, webrequestów itp., itd..

Nie uważam za złe logowanie część normalnego przepływu, to jest wyjątkowe. Zwykle użytkownik wpisuje poprawne hasło, a plik istnieje. Wyjątkowe przypadki są wyjątkowe i doskonale jest używać wyjątków dla nich. Komplikowanie kodu poprzez propagację wartości zwrotnych przez N poziomów w górę stosu jest stratą energii i spowoduje bałagan w kodzie. Zrób najprostszą rzecz, która może zadziałać. Nie Optymalizuj przedwcześnie za pomocą kodów błędów, wyjątkowe rzeczy z definicji rzadko się zdarzają, a wyjątki nic nie kosztują, chyba że je rzucisz.

 22
Author: Bjorn Reppen,
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-16 21:39:01

Wyjątki są dość kosztownym efektem, jeśli na przykład masz użytkownika, który podaje nieprawidłowe hasło, zazwyczaj lepiej jest przekazać flagę błędu lub inny wskaźnik, że jest ona nieprawidłowa.

Wynika to ze sposobu obsługi wyjątków, prawdziwe złe dane wejściowe i unikalne elementy zatrzymania krytycznego powinny być wyjątkami, ale nie nieudane informacje logowania.

 15
Author: Mitchel Sellers,
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-16 21:11:17

Myślę, że powinieneś rzucać wyjątek tylko wtedy, gdy nie możesz nic zrobić, aby wydostać się z obecnego stanu. Na przykład, jeśli przydzielasz pamięć i nie ma żadnej do przydzielenia. W wymienionych przypadkach można wyraźnie odzyskać z tych stanów i może zwrócić kod błędu z powrotem do rozmówcy odpowiednio.


Zobaczysz wiele rad, w tym w odpowiedziach na to pytanie, że należy rzucać wyjątki tylko w "wyjątkowych" okolicznościach. To wydaje się powierzchownie rozsądna, ale jest wadliwą radą, ponieważ zastępuje jedno pytanie ("Kiedy powinienem rzucić wyjątek") innym subiektywnym pytaniem ("co jest wyjątkowe"). Zamiast tego, postępuj zgodnie z radami Herb Sutter (dla C++, dostępne w Dr Dobbs artykuł Kiedy i jak używać WYJĄTKÓW, a także w swojej książce z Andrei Alexandrescu, C++ Coding Standards ): wyrzuć wyjątek wtedy i tylko wtedy, gdy

  • warunek wstępny nie jest spełniony (co zwykle sprawia, że jeden z następujących impossible) lub
  • alternatywa nie spełni warunku post-lub
  • alternatywa nie utrzymałaby niezmiennika.
Dlaczego tak jest lepiej? Czy nie zastępuje to pytania kilkoma pytaniami o warunki wstępne, warunki postwarunkowe i niezmienniki? Jest to lepsze z kilku powiązanych powodów.
  • warunki wstępne, warunki postkondensacyjne i niezmienniki sądesign charakterystyką naszego programu (jego wewnętrznego API), natomiast decyzja o throw jest szczegółem implementacji. Zmusza nas to do brania pod uwagę, że projekt i jego wdrożenie musimy rozpatrywać oddzielnie, a naszym zadaniem przy wdrażaniu metody jest wytworzenie czegoś, co spełnia ograniczenia projektowe.
  • zmusza nas do myślenia w kategoriach warunków wstępnych, postkondensacyjnych i niezmienników, które sątylko założeniami, które callers naszej metody powinny i są wyrażone precyzyjnie, umożliwiając luźne sprzężenie między składniki naszego programu.
  • to luźne sprzężenie pozwala nam na refaktoryzację implementacji, jeśli to konieczne.
  • warunki i niezmienniki są testowalne; daje to kod, który można łatwo przetestować jednostkowo, ponieważ warunki są predykatami, które nasz kod testu jednostkowego może sprawdzić (assert).
  • myślenie w kategoriach post-conditions naturalnie tworzy projekt, który ma sukces jako warunek post-condition , który jest naturalnym stylem używania WYJĄTKÓW. Na normalna ("szczęśliwa") ścieżka wykonania programu jest ułożona liniowo, a cały kod obsługi błędów przeniesiony do klauzul catch.
 13
Author: Raedwald,
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
2018-08-01 11:58:06

Powiedziałbym, że nie ma twardych i szybkich zasad, kiedy używać WYJĄTKÓW. Jednak istnieją dobre powody, aby ich używać lub nie używać:

Powody użycia WYJĄTKÓW:

  • przepływ kodu dla wspólnego przypadku jest jaśniejszy
  • może zwracać złożone informacje o błędach jako obiekt (chociaż można to również osiągnąć za pomocą parametru "out" błędu przekazanego przez odniesienie)
  • języki zazwyczaj zapewniają pewne możliwości zarządzania porządkiem w przypadku wyjątku (try / finally in Java, using in C#, RAII in C++)
  • W przypadku, gdy żaden wyjątek nie zostanie wyrzucony, wykonanie może czasami być szybsze niż sprawdzenie kodów zwrotnych
  • w Javie, zaznaczone wyjątki muszą być zadeklarowane lub przechwycone (choć może to być powodem przeciwko)

Powody, by nie używać WYJĄTKÓW:

  • czasami jest to przesada, jeśli Obsługa błędów jest prosta
  • jeśli wyjątki nie są udokumentowane lub zadeklarowane, mogą być nieuwzględnione przez wywołanie kodu, co może być gorszy niż w przypadku, gdy kod wywołujący po prostu zignorował kod powrotu (wyjście aplikacji vs cicha awaria - co jest gorsze może zależeć od scenariusza)
  • W C++ kod, który używa WYJĄTKÓW, musi być bezpieczny dla WYJĄTKÓW (nawet jeśli nie rzucasz lub nie łapiesz ich, ale wywołujesz funkcję rzucania pośrednio)
  • W C++ trudno powiedzieć, Kiedy funkcja może rzucać, dlatego musisz mieć paranoję na temat bezpieczeństwa WYJĄTKÓW, jeśli ich używasz
  • rzucanie i łapanie wyjątków jest generalnie znacznie droższe w porównaniu do sprawdzania flagi zwrotu

Ogólnie rzecz biorąc, byłbym bardziej skłonny używać WYJĄTKÓW w Javie niż w C++ lub C#, ponieważ jestem zdania, że wyjątek, zadeklarowany lub nie, jest zasadniczo częścią formalnego interfejsu funkcji, ponieważ zmiana gwarancji wyjątku może złamać kod wywołujący. Największą zaletą korzystania z nich w Java IMO jest to, że wiesz, że twój rozmówca musi obsługiwać wyjątek, a to zwiększa szansę na prawidłowe zachowanie.

Z tego powodu, w dowolnym języku, zawsze wyprowadzałbym wszystkie wyjątki w warstwie kodu lub API ze wspólnej klasy, tak aby kod wywołujący zawsze mógł zagwarantować wyłapanie wszystkich wyjątków. Również uważałbym za złe rzucanie klas wyjątków, które są specyficzne dla implementacji, podczas pisania API lub biblioteki(tj. zawijanie WYJĄTKÓW z niższych warstw, aby wyjątek, który odbiera twój rozmówca, był zrozumiały w kontekście twojego interfejsu).

Uwaga że w Javie rozróżnia się wyjątki ogólne i wykonawcze, ponieważ te ostatnie nie muszą być deklarowane. Używałbym klasy WYJĄTKÓW Runtime tylko wtedy, gdy wiesz, że błąd jest wynikiem błędu w programie.

 10
Author: Robert,
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-16 23:28:50

Klasy WYJĄTKÓW są jak" normalne " klasy. Tworzysz nową klasę, gdy" jest " innym typem obiektu, z różnymi polami i różnymi operacjami.

Z reguły powinieneś spróbować zrównoważyć liczbę wyjątków i ich szczegółowość. Jeśli twoja metoda wyrzuca więcej niż 4-5 różnych WYJĄTKÓW, prawdopodobnie możesz połączyć niektóre z nich w bardziej "ogólne" wyjątki (np. w Twoim przypadku "AuthenticationFailedException") i użyć wyjątku wiadomość do szczegółów, co poszło nie tak. O ile twój kod nie obsługuje każdej z nich inaczej, nie musisz tworzyć wielu klas WYJĄTKÓW. A jeśli tak, może powinieneś po prostu zwrócić enum z błędem, który wystąpił. W ten sposób jest trochę czystszy.

 5
Author: Shachar,
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-16 21:14:00

Jeśli jest to kod działający wewnątrz pętli, który prawdopodobnie będzie powodować wyjątki w kółko, to rzucanie WYJĄTKÓW nie jest dobrą rzeczą, ponieważ są one dość powolne dla dużego N. Ale nie ma nic złego w rzucaniu niestandardowych WYJĄTKÓW, jeśli wydajność nie jest problemem. Upewnij się tylko, że masz wyjątek base, który wszystkie dziedziczą, zwany BaseException lub coś w tym stylu. BaseException dziedziczy System.Wyjątek, ale wszystkie wyjątki dziedziczą wyjątek BaseException. Ty może nawet mieć drzewo typów wyjątków do grupowania podobnych typów, ale może to być przesada, ale nie musi być przesadą.

Krótka odpowiedź brzmi: jeśli nie spowoduje to znaczącej kary za wydajność (której nie powinno być, chyba że rzucasz wiele wyjątków), to śmiało.

 5
Author: Charles Graham,
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-16 21:19:22

Zgadzam się z japollock tam -- rzucać akceptację, gdy jesteś niepewny co do wyniku operacji. Wywołania API, dostęp do systemów plików, wywołania baz danych itp. Za każdym razem, gdy przekraczasz "granice" swoich języków programowania.

Chciałbym dodać, zapraszam do rzucenia standardowego wyjątku. Chyba, że masz zamiar zrobić coś " innego "(ignorować, e-mail, log, pokazać, że twitter wieloryb coś zdjęcie, itp), a następnie nie zawracać sobie głowy z niestandardowych WYJĄTKÓW.

 3
Author: dclaysmith,
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-17 00:01:15

Zasada rzucania wyjątków jest dość prosta. robisz to, gdy kod został wprowadzony do NIEODZYSKIWALNEGO stanu nieprawidłowego. jeśli dane zostaną naruszone lub nie możesz cofnąć przetwarzania, które nastąpiło do momentu, musisz je zakończyć. co jeszcze możesz zrobić? twoja logika przetwarzania ostatecznie zawiedzie gdzie indziej. jeśli możesz jakoś odzyskać, zrób to i nie rzucaj wyjątku.

W twoim konkretnym przypadku, jeśli byłeś zmuszony zrobić coś głupiego, jak Zaakceptuj wypłatę pieniędzy i dopiero wtedy sprawdź user / pasword powinieneś zakończyć proces, rzucając wyjątek, aby powiadomić, że stało się coś złego i zapobiec dalszym szkodom.

 3
Author: goran,
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
2011-12-19 11:22:35

Ogólnie rzecz biorąc, chcesz wyrzucić wyjątek dla wszystkiego ,co może się zdarzyć w Twojej aplikacji, co jest "wyjątkowe"

W twoim przykładzie oba te wyjątki wyglądają tak, jakbyś wywoływał je poprzez walidację hasła / nazwy użytkownika. W takim przypadku można argumentować, że nie jest to naprawdę wyjątkowe, że ktoś pomylił nazwę użytkownika / hasło.

Są " wyjątkami "od głównego przepływu UML, ale są bardziej" gałęziami " w przetwarzaniu.

Jeśli próbowałeś uzyskać dostęp Twój plik lub baza danych passwd i nie mógł, byłby to wyjątkowy przypadek i wymagałby rzucenia wyjątku.

 2
Author: Gord,
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-16 21:17:03

Po pierwsze, jeśli użytkownicy twojego API nie są zainteresowani konkretnymi, drobnoziarnistymi awariami, to posiadanie dla nich konkretnych WYJĄTKÓW nie ma żadnej wartości.

Ponieważ często nie można dowiedzieć się, co może być przydatne dla użytkowników, lepszym podejściem jest posiadanie konkretnych wyjątków, ale upewnienie się, że dziedziczą one ze wspólnej klasy (np. STD::exception lub jej pochodne w C++). Pozwala to klientowi wychwycić konkretne wyjątki, jeśli wybierze, lub bardziej ogólny wyjątek, jeśli wybierze nie obchodzi mnie to.

 2
Author: Jason Etheridge,
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-16 21:17:41

Wyjątki są przeznaczone dla zdarzeń, które są nienormalne zachowania, błędy, awarie, i takie. Zachowanie funkcjonalne, błąd użytkownika itp., powinny być obsługiwane przez logikę programu. Ponieważ złe konto lub hasło jest oczekiwaną częścią przepływu logicznego w procedurze logowania, powinno być w stanie poradzić sobie z tymi sytuacjami bez wyjątków.

 2
Author: Joe Skora,
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-16 22:02:53

Mam filozoficzne problemy z używaniem WYJĄTKÓW. Zasadniczo oczekujesz, że wystąpi konkretny scenariusz ,ale zamiast radzić sobie z nim wyraźnie, spychasz problem do rozwiązania " gdzie indziej."A gdzie jest to "gdzie indziej", można się domyśleć.

 2
Author: Dan,
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-17 18:43:45

Powiedziałbym, że generalnie każdy fundamentalizm prowadzi do piekła.

Na pewno nie chciałbyś skończyć z przepływem napędzanym przez wyjątki, ale unikanie WYJĄTKÓW w ogóle jest również złym pomysłem. Musisz znaleźć równowagę między obydwoma podejściami. Nie zrobiłbym tego, aby stworzyć typ wyjątku dla każdej wyjątkowej sytuacji. To nie jest produktywne.

Generalnie preferuję tworzenie dwóch podstawowych typów wyjątków, które są używane w całym systemie: LogicalException i TechnicalException . W razie potrzeby można je dodatkowo rozróżnić według podtypów, ale na ogół nie jest to konieczne.

Wyjątek techniczny oznacza naprawdę nieoczekiwany wyjątek, jak serwer bazy danych jest wyłączony, połączenie z serwisem internetowym rzuciło IOException i tak dalej.

Z drugiej strony wyjątki logiczne są używane do propagowania mniej poważnej błędnej sytuacji na górnych warstwach (ogólnie pewne walidacje wynik).

Proszę zauważyć, że nawet logiczny wyjątek nie jest przeznaczony do regularnego używania do kontrolowania przepływu programu, ale raczej do podkreślenia sytuacji, w której przepływ naprawdę powinien się skończyć. W Javie oba typy WYJĄTKÓW są podklasami RuntimeException , a obsługa błędów jest wysoce zorientowana na aspekt.

Więc w przykładzie login byłoby mądrze stworzyć coś w rodzaju AuthenticationException i rozróżnić konkretne sytuacje po wartościach enum, takich jak UsernameNotExisting, PasswordMismatch itd. Wtedy nie skończy się na posiadaniu ogromnej hierarchii wyjątków i możesz utrzymać bloki połowu na poziomie, który można utrzymać. Możesz również łatwo użyć jakiegoś ogólnego mechanizmu obsługi wyjątków, ponieważ masz wyjątki skategoryzowane i dobrze wiesz, co i jak propagować dla użytkownika.

Naszym typowym zastosowaniem jest wywołanie LogicalException podczas wywołania usługi sieciowej, gdy dane wejściowe użytkownika były nieprawidłowe. Wyjątek dostaje łączony do szczegółów SOAPFault, a następnie ponownie wyłączany do wyjątku na kliencie, co powoduje wyświetlenie błędu walidacji na jednym określonym polu wejściowym strony internetowej, ponieważ wyjątek ma odpowiednie mapowanie do tego pola.

Z pewnością nie jest to jedyna sytuacja: nie musisz klikać w serwis internetowy, aby wyrzucić wyjątek. Możesz to zrobić w każdej wyjątkowej sytuacji (jak w przypadku, gdy musisz szybko zawieść)-wszystko zależy od Twojego uznania.

 2
Author: Petr Macek,
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
2011-09-30 01:44:05

Głównym powodem unikania rzucania wyjątków jest to, że jest wiele kosztów związanych z rzucaniem WYJĄTKÓW.

Jedna rzecz w poniższym artykule stwierdza, że wyjątek dotyczy wyjątkowych warunków i błędów.

Błędna nazwa użytkownika niekoniecznie jest błędem programu, ale błędem użytkownika...

Oto przyzwoity punkt wyjścia dla wyjątków w. NET: http://msdn.microsoft.com/en-us/library/ms229030 (VS. 80). aspx

 1
Author: Sam,
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-16 21:14:43

Rzucanie WYJĄTKÓW powoduje odprężenie stosu, co ma pewien wpływ na wydajność (przyznał, nowoczesne zarządzane środowiska poprawiły się na tym). Wciąż powtarzające się rzucanie i łapanie WYJĄTKÓW w zagnieżdżonej sytuacji byłoby złym pomysłem.

Prawdopodobnie ważniejsze niż to, wyjątki są przeznaczone dla wyjątkowych warunków. Nie powinny być używane do zwykłego przepływu sterowania, ponieważ spowoduje to pogorszenie czytelności kodu.

 1
Author: Arno,
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-16 21:21:14

Mam trzy rodzaje warunków, które łapię.

  1. Złe lub brakujące dane wejściowe nie powinny być wyjątkiem. Użyj zarówno js po stronie klienta, jak i regex po stronie serwera do wykrywania, ustawiania atrybutów i do przodu z powrotem do tej samej strony z wiadomościami.

  2. AppException. Zazwyczaj jest to wyjątek, który wykrywasz i dodajesz do kodu. Innymi słowy są to te, których oczekujesz (plik nie istnieje). Zaloguj go, Ustaw wiadomość i wróć do ogólnego błędu strona. Ta strona zwykle zawiera trochę informacji o tym, co się stało.

  3. Nieoczekiwany wyjątek. To są te, o których nie wiesz. Zaloguj go ze szczegółami i prześlij je do ogólnej strony błędu.

Hope this helps

 1
Author: Michael,
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-16 21:54:36

Bezpieczeństwo jest powiązane z twoim przykładem: nie powinieneś informować atakującego o istnieniu nazwy użytkownika, ale hasło jest błędne. To dodatkowe informacje, których nie musisz udostępniać. Wystarczy powiedzieć " nazwa użytkownika lub hasło jest nieprawidłowe."

 1
Author: anon,
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-16 23:10:36

Prosta odpowiedź brzmi, gdy operacja jest niemożliwa (z powodu aplikacji lub z powodu naruszenia logiki biznesowej). Jeśli wywołana jest metoda i niemożliwe jest wykonanie tego, do czego metoda została napisana, wyrzuć wyjątek. Dobrym przykładem jest to, że konstruktory zawsze rzucają ArgumentExceptions, jeśli instancja nie może być utworzona przy użyciu podanych parametrów. Innym przykładem jest InvalidOperationException, który jest wyrzucany, gdy operacja nie może być wykonana ze względu na stan innego członka lub członków klasy.

W Twoim przypadku, jeśli wywołana jest metoda taka jak Login( nazwa użytkownika, hasło), jeśli nazwa użytkownika jest nieprawidłowa, poprawne jest rzucanie UserNameNotValidException lub PasswordNotCorrectException, jeśli hasło jest nieprawidłowe. Użytkownik nie może być zalogowany przy użyciu podanych parametrów (tzn. jest to niemożliwe, ponieważ naruszałoby to uwierzytelnianie), więc wyrzuć wyjątek. Chociaż mogę mieć twoje dwa wyjątki dziedziczą z ArgumentException.

Powiedziawszy to, jeśli nie chcesz wyrzucać wyjątku, ponieważ błąd logowania może być bardzo powszechny, jedną ze strategii jest zamiast tego stworzenie metody, która zwraca typy, które reprezentują różne błędy. Oto przykład:

{ // class
    ...

    public LoginResult Login(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            return new UserInvalidLoginResult(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            return new PasswordInvalidLoginResult(user, password);
        }
        else
        {
            return new SuccessfulLoginResult();
        }
    }

    ...
}

public abstract class LoginResult
{
    public readonly string Message;

    protected LoginResult(string message)
    {
        this.Message = message;
    }
}

public class SuccessfulLoginResult : LoginResult
{
    public SucccessfulLogin(string user)
        : base(string.Format("Login for user '{0}' was successful.", user))
    { }
}

public class UserInvalidLoginResult : LoginResult
{
    public UserInvalidLoginResult(string user)
        : base(string.Format("The username '{0}' is invalid.", user))
    { }
}

public class PasswordInvalidLoginResult : LoginResult
{
    public PasswordInvalidLoginResult(string password, string user)
        : base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
    { }
}

Większość programistów naucza się unikać WYJĄTKÓW ze względu na koszty spowodowane ich wyrzuceniem. Dobrze jest być świadomym zasobów, ale zazwyczaj nie kosztem projektu aplikacji. To prawdopodobnie jest powód, dla którego powiedziano ci nie rzucać dwóch WYJĄTKÓW. To, czy używać WYJĄTKÓW, czy nie, zwykle sprowadza się do tego, jak często wyjątek będzie występował. Jeśli jest to dość powszechny lub dość wyraźny wynik, to wtedy większość programistów uniknie wyjątków i zamiast tego stworzy inną metodę wskazującą niepowodzenie, z powodu rzekomego zużycia zasobów.

Oto przykład unikania używania WYJĄTKÓW w opisanym scenariuszu, używając wzorca TRY ():

public class ValidatedLogin
{
    public readonly string User;
    public readonly string Password;

    public ValidatedLogin(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            throw new UserInvalidException(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            throw new PasswordInvalidException(password);
        }

        this.User = user;
        this.Password = password;
    }

    public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
    {
        if (IsInvalidUser(user) || 
            IsInvalidPassword(user, password))
        {
            return false;
        }

        validatedLogin = new ValidatedLogin(user, password);

        return true;
    }
}
 1
Author: Chris,
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-17 05:24:54

Moim zdaniem podstawowym pytaniem powinno być, czy można oczekiwać, że rozmówca będzie chciał kontynuować normalny przepływ programu, jeśli wystąpi warunek. Jeśli nie wiesz, albo masz oddzielne metody doSomething i trySomething, gdzie pierwsza zwraca błąd, a druga nie, lub masz procedurę, która akceptuje parametr wskazujący, czy wyjątek powinien zostać wyrzucony, jeśli się nie powiedzie). Rozważ klasę, która wysyła polecenia do zdalnego systemu i raportuje odpowiedzi. Pewne polecenia (np. restart) spowodują, że zdalny system wyśle odpowiedź, ale nie będzie reagował przez pewien czas. W związku z tym przydatne jest, aby móc wysłać polecenie "ping" i dowiedzieć się, czy zdalny system reaguje w rozsądnym czasie bez konieczności rzucania wyjątku, jeśli tak nie jest (dzwoniący prawdopodobnie spodziewałby się, że kilka pierwszych prób "ping" zawiedzie, ale w końcu zadziała). Z drugiej strony, jeśli ktoś ma sekwencję poleceń like:

  exchange_command("open tempfile");
  exchange_command("write tempfile data {whatever}");
  exchange_command("write tempfile data {whatever}");
  exchange_command("write tempfile data {whatever}");
  exchange_command("write tempfile data {whatever}");
  exchange_command("close tempfile");
  exchange_command("copy tempfile to realfile");

Można by chcieć, aby niepowodzenie jakiejkolwiek operacji przerwało całą sekwencję. Chociaż można sprawdzić każdą operację, aby upewnić się, że się powiodła, bardziej pomocne jest, aby funkcja exchange_command() rzuciła wyjątek, jeśli polecenie się nie powiedzie.

W rzeczywistości, w powyższym scenariuszu pomocne może być posiadanie parametru do wyboru wielu trybów obsługi błędów: nigdy nie wyrzucaj WYJĄTKÓW, wyrzucaj wyjątki tylko dla błędów komunikacji lub rzucaj wyjątki w przypadkach, gdy polecenie nie zwraca oznaczenia "sukces".

 1
Author: supercat,
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-06-24 16:45:18

Dla mnie wyjątek powinien być wyrzucony, gdy wymagana reguła techniczna lub biznesowa zawiedzie. na przykład, jeśli jednostka samochodu jest związana z tablicą 4 opon ... jeśli jedna lub więcej opon jest zerowa ... wyjątek powinien być wywołany "NotEnoughTiresException" , ponieważ może być przechwytywany na innym poziomie systemu i ma istotne znaczenie poprzez logowanie. poza tym, jeśli po prostu spróbujemy kontrolować przepływ null i zapobiec instancjacji samochodu . może nigdy nie znajdziemy źródła problemu , bo opona nie powinna być zerowa .

 1
Author: Genjuro,
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
2011-10-06 15:32:51

Możesz użyć trochę ogólnych wyjątków dla tych warunków. Np. ArgumentException jest przeznaczony do użycia, gdy coś pójdzie nie tak z parametrami do metody (z wyjątkiem ArgumentNullException). Generalnie nie potrzebujesz wyjątków takich jak LessThanZeroException, NotPrimeNumberException itp. Pomyśl o użytkowniku swojej metody. Liczba warunków, które będzie chciała dokładnie obsłużyć, jest równa liczbie typów wyjątków, które Twoja metoda trzeba rzucać. W ten sposób możesz określić szczegółowe wyjątki.

Nawiasem mówiąc, zawsze staraj się zapewnić użytkownikom swoich bibliotek pewne sposoby unikania WYJĄTKÓW. TryParse jest dobrym przykładem, istnieje tak, że nie trzeba używać int.Parse i catch wyjątek. W Twoim przypadku możesz podać kilka metod sprawdzania, czy nazwa użytkownika jest poprawna lub hasło jest poprawne, aby użytkownicy (lub ty) nie musieli obsługiwać wielu WYJĄTKÓW. Miejmy nadzieję, że zaowocuje to więcej czytelny kod i lepsza wydajność.

 0
Author: Serhat Ozgel,
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-16 21:19:53

Ostatecznie decyzja sprowadza się do tego, czy bardziej pomocne jest radzenie sobie z błędami na poziomie aplikacji, takimi jak ta, za pomocą obsługi wyjątków, czy za pomocą własnego mechanizmu zwijania, takiego jak zwracanie kodów statusu. Nie wydaje mi się, żeby istniała zasada, która jest lepsza, ale rozważyłbym:

    Kto dzwoni do ciebie? Czy to jakieś publiczne API czy biblioteka wewnętrzna?
  • jakiego języka używasz? Jeśli jest to Java, na przykład, to rzucanie a (zaznaczone) wyjątek stanowi wyraźne obciążenie dla rozmówcy, aby obsłużyć ten warunek błędu w jakiś sposób, w przeciwieństwie do statusu zwrotu, który może zostać zignorowany. To może być dobre lub złe.
  • Jak obsługiwane są inne warunki błędów w tej samej aplikacji? Rozmówcy nie będą chcieli zajmować się modułem, który obsługuje błędy w sposób idiosynkratyczny, w przeciwieństwie do niczego innego w systemie.
  • Jak wiele rzeczy może pójść nie tak z daną rutyną i jak byłyby obsługiwane inaczej? Rozważ różnica między serią bloków catch, które obsługują różne błędy i przełącznik na kod błędu.
  • Czy masz uporządkowaną informację o błędzie, który musisz zwrócić? Rzucenie wyjątku daje lepsze miejsce do umieszczenia tych informacji niż tylko zwracanie statusu.
 0
Author: eli,
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-16 21:26:25

Istnieją dwie główne klasy WYJĄTKÓW:

1) wyjątek systemowy (np. utracone połączenie z bazą danych) lub 2) wyjątek użytkownika. (np. user input validation, 'password is incorrect')

Uważam, że pomocne jest utworzenie własnej klasy WYJĄTKÓW użytkownika i kiedy chcę rzucić błąd użytkownika, chcę być inaczej obsługiwany (ie resourced błąd wyświetlany użytkownikowi), to wszystko, co muszę zrobić w moim głównym programie obsługi błędów, to sprawdzić typ obiektu:

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If
 0
Author: Crusty,
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-17 01:28:33

Kilka przydatnych rzeczy do przemyślenia przy podejmowaniu decyzji, czy wyjątek jest odpowiedni:

  1. Jaki poziom kodu chcesz uruchomić po wystąpieniu wyjątku-czyli ile warstw stosu wywołań powinno się rozwinąć. Zazwyczaj chcesz obsłużyć wyjątek jak najbliżej miejsca, w którym występuje. W przypadku walidacji nazwy użytkownika/hasła Zwykle radzisz sobie z błędami w tym samym bloku kodu, zamiast dopuszczać wyjątek. Wyjątkiem jest więc prawdopodobnie nie na miejscu. (OTOH, po trzech nieudanych próbach logowania, przepływ sterowania może przesunąć się gdzie indziej, a wyjątek może być odpowiedni tutaj.)

  2. Czy to zdarzenie jest czymś, co chciałbyś zobaczyć w dzienniku błędów? Nie każdy wyjątek jest zapisywany do dziennika błędów, ale warto zapytać, czy ten wpis w dzienniku błędów byłby przydatny - tzn. próbowałbyś coś z tym zrobić, czy byłby to śmieci, które ignorujesz.

 0
Author: Mike Kantor,
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-17 02:10:20

"PasswordNotCorrectException" nie jest dobrym przykładem użycia WYJĄTKÓW. Należy się spodziewać, że użytkownicy mylą swoje hasła, więc nie jest to wyjątek IMHO. Prawdopodobnie nawet odzyskujesz po nim, pokazując ładny komunikat o błędzie, więc jest to tylko sprawdzenie ważności.

Nieobsługiwane wyjątki w końcu zatrzymają wykonanie-co jest dobre. Jeśli zwracasz kody false, null lub błędów, będziesz musiał poradzić sobie ze stanem programu samodzielnie. Jeśli zapomnisz sprawdzić warunki gdzieś Twój program może nadal działać z błędnymi danymi, a Ty możesz mieć trudności z ustaleniem co się stało i Gdzie .

Oczywiście możesz spowodować ten sam problem z pustymi poleceniami catch, ale przynajmniej ich wykrycie jest łatwiejsze i nie wymaga zrozumienia logiki.

Więc jako zasada:

Używaj ich tam, gdzie nie chcesz lub po prostu nie możesz odzyskać po błędzie.

 0
Author: DanMan,
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
2011-12-10 11:53:34