Zawsze zmagam się z tym ... próbując znaleźć właściwą równowagę między próbą złapania a kodem, który nie staje się tym nieprzyzwoitym bałaganem tabulatorów, nawiasów i wyjątków, które są wyrzucane z powrotem na stos wywołań jak gorący ziemniak. Na przykład mam teraz rozwijaną aplikację, która korzysta z SQLite. Mam interfejs bazy danych, który wyodrębnia wywołania SQLite, i model, który akceptuje rzeczy wchodzące / wychodzące z bazy danych ... Więc jeśli / kiedy wystąpi wyjątek SQLite, musi zostać podrzucony do modelu (który go nazwał) ), który musi przekazać to osobie, która wywołała AddRecord / DeleteRecord / cokolwiek ...
Jestem fanem wyjątkami, w przeciwieństwie do powrotu kody błędów, ponieważ kody błędów mogą być ignorowane, zapomniane, itd., Podczas gdy w istocie wyjątek musi być obsługiwane (pewnik, że mógł złapać i przenieść się od razu ...) Jestem pewny, że musi być lepszy sposób niż to, o czym teraz mówię.
Edycja: Powinienem to sformułować nieco inaczej. Rozumiem, że rzucam jako różne typy i takie, źle to sformułowałem i to moja wina. Moje pytanie brzmi ... w jaki sposób najlepiej utrzymywać kod w czystości? Z czasem zaczyna mi się wydawać, że jest bardzo zagracony.
źródło
Odpowiedzi:
Pomyśl o tym w kategoriach silnego pisania, nawet jeśli nie używasz silnie napisanego języka - jeśli twoja metoda nie może zwrócić oczekiwanego typu, powinna generować wyjątek.
Ponadto, zamiast rzucać wyjątek SQLException aż do modelu (lub gorzej, interfejsu użytkownika), każda warstwa powinna wychwycić znane wyjątki i zawinąć / zmutować / zastąpić je wyjątkami dostosowanymi do tej warstwy:
Powinno to pomóc ograniczyć liczbę wyjątków, których szukasz w każdej warstwie, i pomóc w utrzymaniu zorganizowanego systemu wyjątków.
źródło
throws SQLException
metodę, która nie oznacza, że SQL jest w to zaangażowany. A co się stanie, jeśli zdecydujesz, że niektóre operacje powinny przejść do magazynu plików? Teraz musisz zadeklarowaćthrows SQLException, IOException
itp. To wymknie się spod kontroli.Wyjątki pozwalają na pisanie czystszego kodu, ponieważ większość z nich zajmuje się normalnym przypadkiem, a wyjątkowe przypadki mogą być obsługiwane później, nawet w innym kontekście.
Reguła obsługi (wychwytywania) wyjątków jest taka, że musi to być zrobione w kontekście, który faktycznie może coś z tym zrobić. Ale to ma wyjątek:
Wyjątki muszą być wychwytywane na granicach modułów (szczególnie na granicach warstw), a nawet aby je zawrzeć, należy rzucić wyjątek wyższego poziomu, który ma znaczenie dla wywołującego.Każdy moduł i warstwa muszą ukrywać szczegóły swojej implementacji nawet w odniesieniu do wyjątków (moduł sterty może generować HeapFull, ale nigdy ArrayIndexOutOfBounds).
W twoim przykładzie jest mało prawdopodobne, aby górne warstwy mogły coś zrobić z wyjątkiem wyjątku SQLite (jeśli tak, to wszystko jest tak połączone z SQLite, że nie będziesz w stanie przełączyć warstwy danych na coś innego). Istnieje kilka przewidywalnych przyczyn niepowodzenia, takich jak dodawanie / usuwanie / aktualizacja, a niektórych z nich (niezgodne zmiany w równoległych transakcjach) nie można odzyskać nawet w warstwie danych / trwałości (naruszenie reguł integralności, fi). Warstwa trwałości powinna tłumaczyć wyjątki na coś znaczącego w terminach warstwy modelowej, aby górne warstwy mogły zdecydować, czy spróbować ponownie, czy z wdziękiem ponieść porażkę.
źródło
Zasadniczo powinieneś wychwytywać tylko określone wyjątki (np. IOException) i tylko wtedy, gdy masz coś konkretnego do zrobienia po złapaniu wyjątku.
W przeciwnym razie często najlepiej jest pozwolić, aby wyjątki wypłynęły na powierzchnię, aby można je było odkryć i rozwiązać. Niektórzy nazywają to niezawodnie.
Powinieneś mieć jakiś moduł obsługi w katalogu głównym aplikacji, aby wychwycić nieobsługiwane wyjątki, które pojawiły się od dołu. Daje to szansę na przedstawienie, zgłoszenie wyjątku lub zarządzanie nim w odpowiedni sposób.
Zawijanie wyjątków jest przydatne, gdy konieczne jest rzucenie wyjątku na system rozproszony, a klient nie ma definicji błędu po stronie serwera.
źródło
Wyobraź sobie, że piszesz klasę stosów. Nie umieszczasz żadnego kodu obsługi wyjątków w klasie, w wyniku czego może wygenerować następujące wyjątki.
Uproszczone podejście do zawijania wyjątków może zdecydować o zawarciu obu tych wyjątków w klasie wyjątków StackError. Jednak tak naprawdę nie ma sensu owijanie wyjątków. Jeśli obiekt zgłosi wyjątek niskiego poziomu, co powinno oznaczać, że obiekt jest uszkodzony. Jest jednak jeden przypadek, w którym jest to do przyjęcia: gdy obiekt jest rzeczywiście uszkodzony.
Celem zawinięcia wyjątków jest to, że obiekt powinien podać odpowiednie wyjątki dla zwykłych błędów. Stos powinien podnieść StackEmpty, a nie ArrayIndexError, gdy wyskakuje z pustego stosu. Zamiarem nie jest aby uniknąć innych wyjątków w przypadku uszkodzenia obiektu lub kodu.
Co my naprawdę chcemy uniknąć, to wychwytywanie wyjątków niskiego poziomu, które zostały przekazane przez obiekty wysokiego poziomu. Klasa stosu, która generuje błąd ArrayIndexError podczas wyskakiwania z pustego stosu, jest drobnym problemem. Jeśli rzeczywiście złapiesz ten ArrayIndexError, mamy poważny problem. Propagowanie błędów niskiego poziomu jest o wiele mniej poważnym grzechem niż łapanie ich.
Aby przywrócić to do przykładu wyjątku SQLException: dlaczego otrzymujesz wyjątki SQLException? Jednym z powodów jest to, że przekazujesz nieprawidłowe zapytania. Jeśli jednak warstwa dostępu do danych generuje złe zapytania, jest zepsuta. Nie powinien próbować ponownie zawijać swojej awarii w wyjątku DataAccessFailure.
Jednak wyjątek SQLEx może również powstać z powodu utraty połączenia z bazą danych. Moją strategią w tym punkcie jest wychwycenie wyjątku na ostatniej linii obrony, zgłoszenie użytkownikowi, że połączenie z bazą danych zostało utracone i zamknięcie. Ponieważ aplikacja utraciła dostęp do bazy danych, naprawdę niewiele można zrobić.
Nie wiem jak wygląda twój kod. Ale wygląda na to, że ślepo tłumaczysz wszystkie wyjątki na wyjątki wyższego poziomu. Powinieneś to robić tylko w stosunkowo niewielkiej liczbie przypadków. Większość wyjątków niższego poziomu wskazuje na błędy w kodzie. Złapanie i przepakowanie ich przynosi efekt przeciwny do zamierzonego.
źródło