Używanie try / catch do zapobiegania awariom aplikacji

79

Pracowałem nad aplikacją na Androida, która try/catchczęsto używa, aby zapobiec awariom nawet w miejscach, w których nie ma takiej potrzeby. Na przykład,

Do widoku w xml layoutz id = toolbarodwołuje się:

// see new example below, this one is just confusing
// it seems like I am asking about empty try/catch
try {
    View view = findViewById(R.id.toolbar);
}
catch(Exception e) {
}

To podejście jest używane w całej aplikacji. Ślad stosu nie jest drukowany i naprawdę trudno jest stwierdzić, co poszło nie tak. Aplikacja zamyka się nagle bez drukowania śladu stosu.

Poprosiłem seniora, żeby mi to wyjaśnił, a on powiedział:

Ma to na celu zapobieganie awariom w produkcji.

Całkowicie się z tym nie zgadzam . Dla mnie nie jest to sposób na zapobieganie awariom aplikacji. Pokazuje, że programista nie wie, co robi i ma wątpliwości.

Czy jest to podejście stosowane w przemyśle w celu zapobiegania awariom aplikacji korporacyjnych?

Jeśli try/catchtak, naprawdę potrzebujemy, to czy możliwe jest dołączenie procedury obsługi wyjątków z wątkiem interfejsu użytkownika lub innymi wątkami i przechwycenie tam wszystkiego? Jeśli to możliwe, będzie to lepsze podejście.

Tak, puste try/catchjest złe i nawet jeśli drukujemy ślad stosu lub rejestrujemy wyjątek na serwerze, try/catchlosowe zawijanie bloków kodu w całej aplikacji nie ma dla mnie sensu, np. Gdy każda funkcja jest ujęta w try/catch.

AKTUALIZACJA

Ponieważ pytanie to wzbudziło wiele uwagi, a niektórzy błędnie je zinterpretowali (być może dlatego, że nie sformułowałem go jasno), zamierzam je przeformułować.

Oto, co robią tutaj programiści

  • Funkcja jest pisana i testowana , może to być mała funkcja, która po prostu inicjuje widoki lub złożona, po przetestowaniu jest zawijana wokół try/catchbloku. Nawet dla funkcji, która nigdy nie zgłosi żadnego wyjątku.

  • Ta praktyka jest stosowana w całej aplikacji. Czasami drukowany jest ślad stosu, a czasami tylko debug logz przypadkowym komunikatem o błędzie. Ten komunikat o błędzie różni się w zależności od programisty.

  • Dzięki takiemu podejściu aplikacja nie ulega awarii, ale zachowanie aplikacji staje się nieokreślone. Nawet czasami trudno jest śledzić, co poszło nie tak.

  • Prawdziwe pytanie, które zadawałem, brzmiało; Czy jest to praktyka stosowana w branży w celu zapobiegania awariom aplikacji korporacyjnych? i nie pytam o puste try / catch . Czy to tak, że użytkownicy uwielbiają aplikacje, które nie ulegają awarii niż aplikacje, które zachowują się nieoczekiwanie? Ponieważ tak naprawdę sprowadza się to do awarii lub pokazania użytkownikowi pustego ekranu lub zachowania, którego użytkownik nie jest świadomy.

  • Wstawiam tutaj kilka fragmentów prawdziwego kodu

      private void makeRequestForForgetPassword() {
        try {
            HashMap<String, Object> params = new HashMap<>();
    
            String email= CurrentUserData.msisdn;
            params.put("email", "blabla");
            params.put("new_password", password);
    
            NetworkProcess networkProcessForgetStep = new NetworkProcess(
                serviceCallListenerForgotPasswordStep, ForgotPassword.this);
            networkProcessForgetStep.serviceProcessing(params, 
                Constants.API_FORGOT_PASSWORD);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
     private void languagePopUpDialog(View view) {
        try {
            PopupWindow popupwindow_obj = popupDisplay();
            popupwindow_obj.showAsDropDown(view, -50, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    void reloadActivity() {
        try {
            onCreateProcess();
        } catch (Exception e) {
        }
    }
    

To nie jest duplikat najlepszych praktyk w zakresie obsługi wyjątków Androida , OP próbuje złapać wyjątek w innym celu niż to pytanie.

mallaudin
źródło
11
Nie odpowiadając na twoje pytanie, ale nigdy nie połykaj powoli wyjątków catch(Exception e){}- ten komentarz miał sens przed edycją pytania
Straszny Wombat
1
patrz stackoverflow.com/questions/6115896/…
Straszny wombat
29
Ach, niesławnyON ERROR RESUME NEXT
Deduplicator
Komentarze nie służą do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Bhargav Rao
1
To pytanie dało mi do myślenia, ponieważ często używam również try {} catch (Exception e) {}, gdy
kończy

Odpowiedzi:

81

Oczywiście zawsze są wyjątki od reguł, ale jeśli potrzebujesz praktycznej reguły - masz rację; puste bloki catch są „absolutnie” złą praktyką.

Przyjrzyjmy się bliżej, zaczynając od konkretnego przykładu:

try {
  View view = findViewById(R.id.toolbar);
}
catch(Exception e) { }

Powstaje więc odniesienie do czegoś; a kiedy to zawiedzie ... to nie ma znaczenia; ponieważ to odniesienie nie jest używane w pierwszej kolejności! Powyższy kod jest absolutnie bezużytecznym szumem liniowym . A może osoba, która napisała ten kod, początkowo zakłada, że ​​drugie, podobne wywołanie w magiczny sposób nie rzuci już wyjątku ?!

Może to miało wyglądać tak:

try {
  View view = findViewById(R.id.toolbar);
  ... and now do something with that view variable ...
}
catch(Exception e) { }

Ale znowu, co to pomaga ?! Istnieją wyjątki do komunikowania się odpowiednio propagować sytuacje błędów w kodzie. Ignorowanie błędów rzadko jest dobrym pomysłem. Właściwie wyjątek można potraktować w następujący sposób:

  • Przekazujesz użytkownikowi opinię; (na przykład: „wprowadzona wartość nie jest ciągiem, spróbuj ponownie”); lub zająć się bardziej złożoną obsługą błędów
  • Może problem jest w jakiś sposób oczekiwany i można go złagodzić (na przykład podając „domyślną” odpowiedź, gdy jakieś „wyszukiwanie zdalne” nie powiodło się)
  • ...

Krótko mówiąc: minimalną rzeczą, którą robisz z wyjątkiem jest rejestrowanie / śledzenie go; tak, że kiedy przyjdziesz później do debugowania jakiegoś problemu, zrozumiesz „OK, w tym momencie zdarzył się wyjątek”.

I jak inni zauważyli: generalnie unikasz również wyłapywania wyjątków (cóż, w zależności od warstwy: mogą być dobre powody, aby złapać jakiś wyjątek , a nawet niektóre rodzaje błędów na najwyższym poziomie, aby upewnić się, że nic się nie gubi; nigdy ).

Na koniec zacytujmy Warda Cunninghama:

Wiesz, że pracujesz z czystym kodem, gdy każda przeczytana procedura okazuje się być prawie taka, jakiej się spodziewałeś. Możesz nazwać to pięknym kodem, gdy kod również sprawia, że ​​wygląda na to, że język został stworzony dla problemu.

Pozwólcie temu zagłębić się i rozmyślajcie o tym. Czysty kod Cię nie zaskakuje. Przykład, który nam pokazujesz, zaskakuje wszystkich .

Aktualizacja dotycząca aktualizacji, o którą pyta PO

try {
  do something
}
catch(Exception e) { 
  print stacktrace
}

Ta sama odpowiedź: robienie tego „wszędzie” również jest złą praktyką. Ponieważ ten kod również zaskakuje czytelnika.

Powyższe:

  • Wyświetla gdzieś informacje o błędzie. Nie ma żadnej gwarancji, że to „gdzieś” przypomina rozsądne miejsce docelowe. W przeciwieństwie. Przykład: w aplikacji, z którą pracuję, takie wywołania magicznie pojawiałyby się w naszych buforach śledzenia. W zależności od kontekstu, nasza aplikacja może czasami pompować tony danych do tych buforów; sprawiając, że te bufory są przycinane co kilka sekund. Dlatego „zwykłe drukowanie błędów” często oznacza: „po prostu utrata wszystkich takich informacji o błędach”.
  • Następnie: nie rób try / catch, bo mogą . Robisz to, ponieważ rozumiesz, co robi Twój kod; i wiesz: lepiej spróbuję złapać tutaj, żeby zrobić właściwą rzecz (zobacz jeszcze raz pierwszą część mojej odpowiedzi).

Więc używając try / catch jako „wzorca”, tak jak pokazujesz; jest jak powiedział: nadal nie jest to dobry pomysł. I tak, zapobiega awariom; ale prowadzi do wszelkiego rodzaju „nieokreślonych” zachowań. Wiesz, kiedy po prostu łapiesz wyjątek, zamiast odpowiednio sobie z nim radzić; otwierasz puszkę robaków; ponieważ możesz napotkać mnóstwo następczych błędów, których później nie rozumiesz. Ponieważ wcześniej wykorzystałeś zdarzenie „główna przyczyna”; wydrukował to gdzieś; i to gdzieś już nie ma.

GhostCat
źródło
1
Co się stanie, jeśli wydrukuję ślad stosu? Nadal nie sądzę, że muszę tu spróbować / złapać.
mallaudin
3
Muszę przyznać, że nie dostaję twojej edycji. Nie mam pojęcia, co tam robisz; lub dokąd z tym zmierzasz.
GhostCat
@mallaudin w ogólnym przypadku wszystko po linii powodującej awarię programu nie zostanie wykonane (obvs), więc drukowanie jest po prostu nonsensem. W tym konkretnym przypadku, tj. Try + except, przynajmniej coś by się pokazało i wyjątek nie zostałby wyciszony.
Peter Badida,
2
@GhostCat OP mówi w komentarzu w innej odpowiedzi, że bloki wyjątków już zawierają wywołania rejestrowania. Pytanie błędnie przedstawia, co się naprawdę dzieje, więc nie sądzę, aby oskarżanie starszego programisty o niekompetencję jest tutaj pomocne. Myślę, że dzieje się coś więcej niż tylko to, co daje nam PO.
jpmc26
1
@GhostCat nie chodzi o repozytorium, właśnie zdałem sobie sprawę, że mój przykład jest zły. Wszyscy myśleli, że pytam o pusty try / catch
mallaudin
15

Z dokumentacji Androida :

Nazwijmy to jako -

Nie łapaj ogólnego wyjątku

Kuszące może być również leniwość podczas wychwytywania wyjątków i zrobienie czegoś takiego:

try {
    someComplicatedIOFunction();        // may throw IOException
    someComplicatedParsingFunction();   // may throw ParsingException
    someComplicatedSecurityFunction();  // may throw SecurityException
    // phew, made it all the way
} catch (Exception e) {                 // I'll just catch all exceptions
    handleError();                      // with one generic handler!
}

W prawie wszystkich przypadkach wyłapywanie ogólnych Exceptionlub Throwable jest niewłaściwe (najlepiej nie Throwable, ponieważ zawiera wyjątki Error). Jest to bardzo niebezpieczne, ponieważ oznacza, że ​​wyjątki, których nigdy się nie spodziewałeś (w tym RuntimeExceptionspodobne ClassCastException), zostają złapane w obsłudze błędów na poziomie aplikacji.

Zasłania on właściwości obsługi błędów w kodzie, co oznacza, że ​​jeśli ktoś doda nowy typ Exceptiondo wywoływanego kodu, kompilator nie pomoże Ci zdać sobie sprawy, że musisz inaczej obsłużyć błąd .

Alternatywy do łapania ogólnych wyjątków:

  • Po jednej próbie złap każdy wyjątek osobno jako oddzielne bloki catch. Może to być niewygodne, ale nadal jest lepsze niż wyłapywanie wszystkich wyjątków.
    Edytuj według autora: To jest mój wybór. Uważaj na powtarzanie zbyt dużej ilości kodu w blokach catch. Jeśli używasz Java 7 lub nowszej, użyj multi-catch, aby uniknąć powtarzania tego samego bloku catch.
  • Zmień kod, aby uzyskać bardziej szczegółową obsługę błędów , z wieloma blokami try. Oddziel IO od parsowania, osobno obsługuj błędy w każdym przypadku.
  • Ponownie wyrzuć wyjątek . Wiele razy i tak nie musisz przechwytywać wyjątku na tym poziomie, po prostu pozwól metodzie go zgłosić.

W większości przypadków nie powinieneś traktować w ten sam sposób różnych typów wyjątków.

Formatowanie / akapity nieznacznie zmienione w stosunku do źródła tej odpowiedzi.

PS Nie bój się wyjątków !! Są przyjaciółmi!!!

Paresh P.
źródło
1
jeśli złapiesz każdy wyjątek osobno, upewnij się, że unikasz kontynuowania wykonywania w stanie niepewnym (unikaj rzeczy takich jak Object a; try { a = thing(); } catch (Exception e) {...} try { a.action(); } catch (Exception e) {...}))
njzk2
Aby być uczciwym, przechwytywanie generycznych Exceptionmoże być przydatne jako część systemu "log-before-crash", chociaż w takim przypadku powinno być ponownie.
Justin Time - Przywróć Monikę
9

Dodałbym to jako komentarz do innej odpowiedzi, ale nie mam jeszcze takiej reputacji.

Masz rację, mówiąc, że jest to zła praktyka, w rzeczywistości to, co opublikowałeś, pokazuje różne rodzaje złych praktyk w odniesieniu do wyjątków.

  1. Brak obsługi błędów
  2. Generic Catch
  3. Brak celowych wyjątków
  4. Koc Spróbuj / złap

Spróbuję to wszystko wyjaśnić na tym przykładzie.

try {
   User user = loadUserFromWeb();     
   if(user.getCountry().equals("us")) {  
       enableExtraFields();
   }
   fillFields(user);   
} catch (Exception e) { 
}

Może to się nie powieść na kilka sposobów, które należy traktować inaczej.

  1. Pola nie będą wypełnione, więc użytkownikowi wyświetlany jest pusty ekran, a potem ... co? Nic - brak obsługi błędów.
  2. Nie ma rozróżnienia między różnymi typami błędów, np. Problemy z Internetem lub problemy z samym serwerem (awaria, zepsute żądanie, uszkodzona transmisja, ...) - Generic catch.
  3. Nie możesz używać wyjątków do własnych celów, ponieważ obecny system to przeszkadza. - Brak celowych wyjątków
  4. Nieistotne i nieoczekiwane błędy (np. Null.equals (...)) mogą spowodować, że niezbędny kod nie zostanie wykonany. - Wypróbuj / złap koc

Rozwiązania

(1) Po pierwsze, cicha porażka nie jest dobra. Jeśli wystąpi awaria, aplikacja nie będzie działać. Zamiast tego należy podjąć próbę rozwiązania problemu lub wyświetlić ostrzeżenie, na przykład „Nie można załadować danych użytkownika, może nie masz połączenia z Internetem?”. Jeśli aplikacja nie robi tego, co powinna, jest to o wiele bardziej frustrujące dla użytkownika, niż gdyby po prostu się zamknęła.

(4) Jeśli Użytkownik jest niekompletny, np. Kraj nie jest znany i zwraca wartość null. Metoda equals utworzy wyjątek NullPointerException. Jeśli ten NPE zostanie po prostu wyrzucony i przechwycony jak powyżej, metoda fillFields (user) nie zostanie wywołana, mimo że nadal można ją bezproblemowo wykonać. Można temu zapobiec, włączając sprawdzanie wartości null, zmieniając kolejność wykonywania lub dostosowując zakres try / catch. (Lub możesz zapisać kodowanie w ten sposób: "nas" .equals (user.getCountry ()), ale musiałem podać przykład). Oczywiście każdy inny wyjątek również uniemożliwi wykonanie funkcji fillFields (), ale jeśli nie ma użytkownika, prawdopodobnie i tak nie chcesz, aby było ono wykonywane.

(1, 2, 3) Ładowanie z sieci WWW często generuje różne wyjątki, od wyjątku IOException do HttpMessageNotReadable, a nawet po prostu zwracanie. Możliwe, że użytkownik nie jest połączony z Internetem, może nastąpiła zmiana na serwerze zaplecza lub jest on wyłączony, ale nie wiesz, ponieważ przechwytujesz (wyjątek) - zamiast tego powinieneś przechwytywać określone wyjątki. Możesz nawet złapać kilka z nich

try{
   User user = loadUserFromWeb(); //throws NoInternetException, ServerNotAvailableException or returns null if user does not exist
   if(user == null) { 
       throw new UserDoesNotExistException(); //there might be better options to solve this, but it highlights how exceptions can be used.
   }
   fillFields(user);
   if("us".equals(user.getCountry()) {
       enableExtraFields();
   }
} catch(NoInternetException e){
    displayWarning("Your internet conneciton is down :(");
} catch(ServerNotAvailableException e){
    displayWarning("Seems like our server is having trouble, try again later.");
} catch(UserDoesNotExistException e){
    startCreateUserActivity();
}

Mam nadzieję, że to wyjaśnia.

Przynajmniej jako szybką naprawę możesz wysłać zdarzenie do zaplecza z wyjątkiem. Na przykład przez firebase lub crashlytics. W ten sposób możesz przynajmniej zobaczyć takie rzeczy jak (hej, główna aktywność nie ładuje się dla 80% naszych użytkowników z powodu problemu takiego jak (4).

Syzygy
źródło
8

To zdecydowanie zła praktyka programistyczna.

Z obecnego scenariusza, jeśli jest ich setki try catch, nie będziesz nawet wiedział, gdzie występuje wyjątek bez debugowania aplikacji, co jest koszmarem, jeśli Twoja aplikacja znajduje się w środowisku produkcyjnym.

Ale możesz dołączyć rejestrator, aby wiedzieć, kiedy zgłaszany jest wyjątek (i dlaczego). Nie zmieni to Twojego normalnego przepływu pracy.

...
try {
    View view = findViewById(R.id.toolbar);
}catch(Exception e){
    logger.log(Level.SEVERE, "an exception was thrown", e);
}
...
Raman Sahasi
źródło
7

To zła praktyka. Inne odpowiedzi mówią tak, ale myślę, że ważne jest, aby cofnąć się i zrozumieć, dlaczego mamy wyjątki.

Każda funkcja ma warunek końcowy - zestaw rzeczy, które muszą być spełnione po wykonaniu tej funkcji. Na przykład funkcja odczytująca z pliku ma warunek post, że dane w pliku zostaną odczytane z dysku i zwrócone. Wyjątek jest zatem generowany, gdy funkcja nie była w stanie spełnić jednego z warunków końcowych.

Ignorując wyjątek od funkcji (lub nawet skutecznie go ignorując, po prostu rejestrując wyjątek), mówisz, że nie przeszkadza ci ta funkcja, która tak naprawdę nie wykonuje całej pracy, na którą się zgodził. Wydaje się to mało prawdopodobne - jeśli funkcja nie działa poprawnie, nie ma gwarancji, że to, co następuje, w ogóle zadziała. A jeśli reszta twojego kodu działa dobrze, niezależnie od tego, czy dana funkcja działa do końca, to można się zastanawiać, dlaczego masz tę funkcję w pierwszej kolejności.

[Teraz są pewne przypadki, w których puste catches są w porządku. Na przykład rejestrowanie jest czymś, co można uzasadnić zawijaniem pustego połowu. Twoja aplikacja prawdopodobnie będzie działać dobrze, nawet jeśli nie będzie można zapisać niektórych danych logowania. Ale są to szczególne przypadki, w których trzeba naprawdę ciężko pracować, aby znaleźć je w normalnej aplikacji.]

Chodzi o to, że jest to zła praktyka, ponieważ tak naprawdę nie powoduje to, że aplikacja działa (rzekome uzasadnienie tego stylu). Być może technicznie system operacyjny go nie zabił. Ale jest mało prawdopodobne, aby aplikacja nadal działała poprawnie po zignorowaniu wyjątku. W najgorszym przypadku może to faktycznie wyrządzić szkodę (np. Uszkodzić pliki użytkownika itp.).

JoshG79
źródło
3

Jest to złe z wielu powodów:

  1. Co ty robisz findViewById powoduje wyjątek? Napraw to (i powiedz mi, bo nigdy tego nie widziałem) zamiast łapać.
  2. Nie łap Exception kiedy możesz złapać określony typ wyjątku.
  3. Istnieje przekonanie, że dobre aplikacje nie ulegają awarii. To nieprawda. Dobra aplikacja ulega awarii, jeśli musi.

Jeśli aplikacja przejdzie w zły stan, znacznie lepiej jest zawiesić ją, niż ciągnąć w stanie bezużytecznym. Kiedy widzi się NPE, nie należy po prostu trzymać się czeku zerowego i odchodzić. Lepszym podejściem jest ustalenie, dlaczego coś jest zerowe i albo powstrzymanie tego przed byciem null, albo (jeśli null stanie się prawidłowym i oczekiwanym stanem) sprawdź, czy nie ma wartości null. Ale musisz zrozumieć, dlaczego problem występuje w pierwszej kolejności.

AJ
źródło
2

Tworzę aplikacje na Androida przez ostatnie 4-5 lat i nigdy nie użyłem try catch do inicjalizacji widoku.

Jeśli jest to pasek narzędzi, zrób to w ten sposób

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

np: - Aby uzyskać TextView z widoku (fragment / dialog / dowolny niestandardowy widok)

TextView textview = (TextView) view.findViewById(R.id.viewId);

TextView textview = (TextView) view.findViewById (R.id.viewId);

zamiast tego

View view = findViewById(R.id.toolbar);

Obiekt widoku ma minimalny zasięg w porównaniu do jego rzeczywistego typu widoku.

Uwaga: - Możliwe, że się zawiesił, ponieważ widok został załadowany. Ale dodanie próby złapania jest złą praktyką.

shijin
źródło
W wielu przypadkach rzutowanie widoku nie jest konieczne. Istnieje kilka metod, Viewktóre mogą być już przydatne (np. setVisibility()), Bez określania dokładnie, która klasa jest używana. (na przykład w przypadku układu, który od czasu do czasu może ulec zmianie)
njzk2
1

Tak, try / catch służy do zapobiegania awariom aplikacji, ale z pewnością nie potrzebujesz try / catch do pobrania widoku z XML, jak przedstawiono w pytaniu.

try / catch jest zwykle używane podczas wykonywania dowolnego żądania http, podczas przetwarzania dowolnego ciągu znaków do adresu URL, tworzenia połączeń URL itp., a także upewnij się, że drukujesz ślad stosu. Brak drukowania nie ma większego sensu w otaczaniu go try / catch.

Chandrani Chatterjee
źródło
1

Jak wspomniano wcześniej, nie należy łapać ogólnych wyjątków, a przynajmniej tylko w kilku centralnych miejscach (zwykle zlokalizowanych w kodzie frameworka / infrastruktury, a nie w kodzie aplikacji). W przypadku wychwytywania wyjątków ogólnych i rejestrowania go, aplikacja powinna zostać później zamknięta lub przynajmniej użytkownik powinien zostać poinformowany, że aplikacja jest potencjalnie w stanie niestabilnym i może dojść do uszkodzenia danych (jeśli użytkownik zdecyduje się kontynuować wykonywanie). Ponieważ tak może się zdarzyć, jeśli złapiesz wszelkiego rodzaju wyjątki (zabraknie pamięci, aby je nazwać) i pozostawisz aplikację w niezdefiniowanym stanie.

IMHO gorzej jest połknąć wyjątki i ryzykować integralność danych, utratę danych lub po prostu pozostawić aplikację w nieokreślonym stanie, niż pozwolić, aby aplikacja uległa awarii, a użytkownik wie, że coś poszło nie tak i może spróbować ponownie. Spowoduje to również lepsze zgłaszanie problemów (bardziej u źródła problemu), prawdopodobnie mniej różnych objawów, niż gdyby użytkownicy zaczęli zgłaszać wszelkiego rodzaju problemy wynikające z niezdefiniowanego stanu aplikacji.

Po wdrożeniu centralnej obsługi / rejestrowania / raportowania wyjątków i kontrolowanego zamykania należy rozpocząć przepisywanie obsługi wyjątków, aby wychwycić lokalne wyjątki tak szczegółowe, jak to tylko możliwe. Postaraj się, aby blok try {} był jak najkrótszy.

DavWEB
źródło
1

Pozwólcie, że dodam mój punkt widzenia, jako faceta pracującego w branży rozwoju urządzeń mobilnych od ponad dziesięciu lat. Najpierw kilka ogólnych wskazówek dotyczących wyjątków, większość z nich znajduje się w powyższych odpowiedziach:

  • Wyjątki powinny być używane w wyjątkowych, nieoczekiwanych lub niekontrolowanych sytuacjach, a nie regularnie w całym kodzie.
  • Programista musi znać fragmenty kodu, które mogą rzucać wyjątki i próbować je przechwytywać, pozostawiając resztę kodu tak czystą, jak to tylko możliwe.
  • Co do zasady wyjątki nie powinny być przemilczane.

Teraz, gdy nie tworzysz aplikacji dla siebie, ale dla firmy lub korporacji, często spotykasz dodatkowe wymagania w tym temacie:

  • „Awarie aplikacji pokazują zły wizerunek firmy, więc są nie do przyjęcia”. Następnie należy przeprowadzić ostrożny rozwój, a wychwycenie nawet nieprawdopodobnych wyjątków może być opcją. Jeśli tak, należy to robić selektywnie i utrzymywać w rozsądnych granicach. Zauważ, że rozwój to nie tylko linie kodu, na przykład w takich przypadkach krytyczny jest intensywny proces testowania. Jednak nieoczekiwane zachowanie aplikacji korporacyjnej jest gorsze niż awaria. Tak więc za każdym razem, gdy złapiesz wyjątek w swojej aplikacji, musisz wiedzieć, co zrobić, co pokazać i jak aplikacja będzie się dalej zachowywać. Jeśli nie możesz tego kontrolować, lepiej pozwól aplikacji się zawiesić.
  • „Dzienniki i ślady stosu mogą zrzucać poufne informacje na konsolę. Może to zostać wykorzystane przez atakującego, więc ze względów bezpieczeństwa nie można ich używać w środowisku produkcyjnym”. To wymaganie jest sprzeczne z ogólną zasadą, że programista nie pisze cichych wyjątków, więc musisz znaleźć na to sposób. Na przykład Twoja aplikacja może kontrolować środowisko, więc używa dzienników i śladów stosu w środowiskach nieprodukcyjnych, jednocześnie korzystając z narzędzi opartych na chmurze, takich jak bugsense, crashlitics lub podobnych w środowiskach produkcyjnych.

Krótka odpowiedź jest taka, że ​​znaleziony kod nie jest przykładem dobrej praktyki, ponieważ jest trudny i kosztowny w utrzymaniu bez poprawy jakości aplikacji.

Miguel
źródło
1

Z innej perspektywy, ponieważ ktoś, kto codziennie pisze oprogramowanie dla przedsiębiorstw, jeśli aplikacja zawiera nieodwracalny błąd, chcę , aby się zawiesił. Rozbijanie się jest pożądane. Jeśli ulegnie awarii, zostanie zarejestrowany. Jeśli zawiesza się więcej niż kilka razy w krótkim czasie, otrzymuję wiadomość e-mail z informacją, że aplikacja ulega awarii i mogę sprawdzić, czy nasza aplikacja i wszystkie używane przez nas usługi internetowe nadal działają.

Więc pytanie:

Jest

try{
  someMethod();
}catch(Exception e){}

dobra praktyka? Nie! Oto kilka punktów:

  1. NAJWAŻNIEJSZA rzecz: to zła obsługa klienta. Skąd mam wiedzieć, że dzieje się coś złego? Moi klienci próbują używać mojej aplikacji i nic nie działa. Nie mogą sprawdzić swojego konta bankowego, opłacić rachunków, cokolwiek robi moja aplikacja. Moja aplikacja jest całkowicie bezużyteczna, ale hej, przynajmniej się nie zawiesiła! (Część mnie wierzy, że ten „starszy” programista dostaje dodatkowe punkty za niską liczbę awarii, więc grają w system).

  2. Kiedy robię programowanie i piszę zły kod, jeśli po prostu łapię i połykam wszystkie wyjątki w górnej warstwie, nie mam logowania. Nie mam nic w konsoli, a moja aplikacja cicho nie działa. Z tego, co wiem, wszystko wydaje się działać dobrze. Więc zatwierdzam kod ... Okazuje się, że mój obiekt DAO był przez cały czas zerowy, a płatności klienta w rzeczywistości nigdy nie były aktualizowane w DB. Ups! Ale moja aplikacja nie uległa awarii, więc to plus.

  3. Udając adwokata diabła, powiedzmy, że nie przeszkadza mi łapanie i połykanie każdego wyjątku. To bardzo proste , aby napisać klasę obsługi wyjątku w Androidzie. Jeśli naprawdę musisz złapać każdy wyjątek, możesz to zrobić w jednym miejscu i nie zasypywać try/catchcałej bazy kodu.

Niektórzy deweloperzy, z którymi pracowałem w przeszłości, uważali, że awarie były złe.

Muszę ich zapewnić, że chcemy , aby nasza aplikacja uległa awarii. Nie, niestabilna aplikacja nie jest w porządku, ale awaria oznacza, że ​​zrobiliśmy coś źle i musimy to naprawić. Im szybciej się zawiesza, tym wcześniej go znajdziemy, tym łatwiej jest to naprawić. Jedyną inną opcją, jaką przychodzi mi do głowy, jest umożliwienie użytkownikowi kontynuowania zepsutej sesji, co utożsamiam z wkurzaniem mojej bazy użytkowników.

Christopher Schneider
źródło
0

Jest to zła praktyka, catch(Exception e){}ponieważ zasadniczo ignorujesz błąd. Prawdopodobnie chcesz zrobić coś bardziej na przykład:

try {
    //run code that could crash here
} catch (Exception e) {
    System.out.println(e.getMessage());
}
Chris
źródło
0

W zasadzie używamy tej samej logiki. Służy try-catchdo zapobiegania awariom aplikacji produkcyjnych.

NIGDY nie należy ignorować wyjątków . To zła praktyka kodowania. Facetom zajmującym się kodem będzie naprawdę trudno zlokalizować część kodu, która wywołała wyjątek, jeśli nie zostaną zalogowani.

Używamy Crashlyticsdo rejestrowania wyjątków. Kod nie ulegnie awarii (ale niektóre funkcje zostaną zakłócone). Ale dziennik wyjątków pojawia się na pulpicie nawigacyjnym programu Fabric/Crashlytics. Możesz przejrzeć te dzienniki i naprawić wyjątki.

try {
    codeThatCouldRaiseError();
} catch (Exception e) {
    e.printStackTrace();
    Crashlytics.logException(e);
}
K Neeraj Lal
źródło
Tak. To właśnie robią tutaj ludzie, ale ja się z tym nie zgadzam. Dlatego zadałem pytanie. Czy możesz wymyślić coś bardziej logicznego?
mallaudin
4
@mallaudin Nie wysyłaj przykładowego kodu, który błędnie przedstawia kod, o który pytasz. Może drastycznie zmienić otrzymaną odpowiedź.
jpmc26
@ jpmc26 yes. Widziałem to w odpowiedziach.
mallaudin
0

Chociaż zgadzam się z innymi odpowiedziami, jest jedna okoliczność, z którą wielokrotnie się spotykałem, w której ten motyw jest marginalnie tolerowany. Załóżmy, że ktoś napisał fragment kodu dla klasy w następujący sposób:

private int foo=0;

    . . .

public int getFoo() throws SomeException { return foo; }

W takiej sytuacji metoda „getFoo ()” nie może zawieść - zawsze będzie zwrócona prawidłowa wartość pola prywatnego „foo”. Jednak ktoś - prawdopodobnie z powodów pedantycznych - zdecydował, że ta metoda powinna zostać uznana za potencjalnie rzucającą Wyjątek. Jeśli następnie spróbujesz wywołać tę metodę w kontekście - np. Program obsługi zdarzeń - który nie pozwala na wyrzucenie wyjątku, jesteś w zasadzie zmuszony do użycia tej konstrukcji (nawet wtedy zgadzam się, że należy przynajmniej zarejestrować wyjątek po prostu w przypadku) . Ilekroć muszę to zrobić, zawsze przynajmniej dodaję duży, gruby komentarz „TO NIE MOŻE WYSTĄPIĆ” obok klauzuli „catch”.

PMar
źródło