Natknąłem się na debatę między kilkoma przyjaciółmi i mną. Wolą ogólne wyjątki, takie jak ClientErrorException
i ServerErrorException
ze szczegółami jako pola wyjątku, podczas gdy ja wolę sprecyzować rzeczy. Na przykład mogę mieć kilka wyjątków, takich jak:
BadRequestException
AuthenticationFailureException
ProductNotFoundException
Każdy z nich zbudowany w oparciu o kod błędu zwrócony z interfejsu API.
Po zaletach wyjątków wydaje się to idiomatyczne dla Javy. Jednak opinia moich przyjaciół nie jest niczym niezwykłym.
Czy istnieje preferowany sposób pod względem czytelności kodu i użyteczności interfejsu API, czy naprawdę sprowadza się to do preferencji?
abstract
i uogólnić klasy wyjątków za pomocą metod pobierających, a następnie sprawić, by te szczegółowe były rozszerzane o ogólne. NpAuthenticationFaliureException extends ClientErrorException
. W ten sposób każdy użytkownik może wybrać sposób postępowania z wyjątkami. Oczywiście, to działa więcej. Jednak podczas pisania aplikacji (zamiast biblioteki) jest to inna sytuacja IMHO. W takim przypadku wyjątki nie byłyby bardziej szczegółowe niż potrzebujesz, dla uproszczenia.Odpowiedzi:
Główną różnicą między posiadaniem wielu różnych klas wyjątków, a posiadaniem tylko kilku, z bardziej szczegółowymi informacjami w tekście błędu (na przykład), jest to, że wiele różnych klas wyjątków pozwala kodowi wywołującemu reagować w różny sposób na różne rodzaje błędów, mając jednocześnie tylko kilka klas ułatwia obsługę wszystkich wyjątków w jednolity sposób.
Jest to zazwyczaj kompromis. Do pewnego stopnia można go ograniczyć, stosując dziedziczenie (ogólną podstawową klasę wyjątków dla osób dzwoniących, które chcą łapać i rejestrować wszystko ogólnie, oraz wyprowadzając wyjątki od tej klasy podstawowej dla osób wywołujących, które potrzebują różnych reakcji), ale nawet to może dać dużo niepotrzebnej złożoności, jeśli nie będziesz ostrożny i trzymasz się zasady YAGNI. Tak więc główne pytanie powinno być tutaj:
Nie ma na to jednego uniwersalnego rozwiązania, nie ma „najlepszej praktyki” braindead, którą można zastosować wszędzie. Odpowiedź na to pytanie zależy w dużej mierze od rodzaju projektowanego oprogramowania lub komponentu:
jakąś aplikację, w której ty lub zespół masz całą bazę kodu pod kontrolą?
lub jakiś element wielokrotnego użytku dla stron trzecich, w którym nie znasz wszystkich potencjalnych rozmówców?
długo działająca aplikacja serwerowa, w której różnego rodzaju błędy nie powinny natychmiast uszkodzić całego systemu i mogą wymagać różnego rodzaju ograniczania błędów?
krótkotrwały proces aplikacji, w którym w przypadku błędu wystarczy wyświetlić komunikat o błędzie użytkownikowi, a następnie ponownie uruchomić proces?
Im więcej wiesz o potencjalnych dzwoniących komponencie, tym lepiej możesz wybrać odpowiedni poziom szczegółowości wyjątków.
źródło
Odpowiedź zależy od tego, o jakim poziomie raportowania błędów mówimy.
Zasadniczo zgadzam się z przyjaciółmi, nie powinieneś nadawać im bardziej szczegółowego charakteru, niż jest to konieczne do wyjaśnienia przyczyny problemu.
Jeśli istnieje powszechny, dobrze znany wyjątek odwoływania się do wartości null (NullReferenceException), nie należy tworzyć własnego MyObjectIsNullException. To tylko dodałoby warstwę zamieszania dla ludzkiego tłumacza, dodatkową rzecz do nauczenia, która niczego nie wyjaśnia.
Tylko wtedy, gdy wyjątek jest wyjątkowy, że nie ma żadnego predefiniowanego, który obejmowałby główną przyczynę, jeśli należy utworzyć własny.
Nie musisz jednak na tym poprzestawać. Typowy błąd może wystąpić w jednym z twoich komponentów i możesz chcieć przekazać, że wystąpił problem z twoim komponentem . Więc nie tylko to, co poszło nie tak, ale także gdzie. Wtedy właściwe byłoby zawinięcie pierwszego wyjątku w MyComponentException. To da ci najlepsze z obu światów.
Najpierw będzie jasne, że twój komponent wpadł w kłopoty. Na dolnej dźwigni konkretną przyczyną byłby wewnętrzny wyjątek.
źródło