Verwenden von try / catch, um Abstürze der App zu verhindern


79

Ich habe an einer Android-App gearbeitet, die try/catchhäufig verwendet wird, um zu verhindern, dass sie selbst an Orten abstürzt, an denen keine Notwendigkeit besteht. Zum Beispiel,

Eine Ansicht in xml layoutmit id = toolbarwird wie folgt referenziert:

// 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) {
}

Dieser Ansatz wird in der gesamten App verwendet. Die Stapelverfolgung wird nicht gedruckt und es ist wirklich schwer zu finden, was schief gelaufen ist. Die App wird plötzlich geschlossen, ohne dass eine Stapelverfolgung gedruckt werden muss.

Ich bat meinen Senior, es mir zu erklären, und er sagte:

Dies dient dazu, Abstürze in der Produktion zu verhindern.

Ich bin damit überhaupt nicht einverstanden . Für mich ist dies nicht der Weg, um Apps vor Abstürzen zu schützen. Es zeigt, dass der Entwickler nicht weiß, was er tut, und Zweifel hat.

Wird dieser Ansatz in der Industrie verwendet, um Abstürze von Unternehmensanwendungen zu verhindern?

Wenn try/catches wirklich, wirklich unser Bedürfnis ist, ist es dann möglich, einen Ausnahmebehandler mit UI-Thread oder anderen Threads anzuhängen und dort alles abzufangen? Das wird nach Möglichkeit ein besserer Ansatz sein.

Ja, leer try/catchist schlecht, und selbst wenn wir eine Stapelverfolgung oder eine Protokollausnahme auf dem Server drucken try/catch, ist es für mich nicht sinnvoll , Codeblöcke zufällig über die gesamte App zu verpacken , z. B. wenn jede Funktion in a eingeschlossen ist try/catch.

AKTUALISIEREN

Da diese Frage viel Aufmerksamkeit erhalten hat und einige Leute die Frage falsch interpretiert haben (vielleicht weil ich sie nicht klar formuliert habe), werde ich sie umformulieren.

Hier ist, was Entwickler hier tun

  • Eine Funktion wird geschrieben und getestet . Es kann sich um eine kleine Funktion handeln, die nur Ansichten initialisiert, oder um eine komplexe Funktion. Nach dem Testen wird sie um einen try/catchBlock gewickelt . Auch für Funktionen, die niemals eine Ausnahme auslösen.

  • Diese Vorgehensweise wird in der gesamten Anwendung angewendet. Manchmal wird eine Stapelverfolgung gedruckt und manchmal nur eine debug logzufällige Fehlermeldung. Diese Fehlermeldung unterscheidet sich von Entwickler zu Entwickler.

  • Bei diesem Ansatz stürzt die App nicht ab, aber das Verhalten der App wird unbestimmt. Selbst manchmal ist es schwer zu verfolgen, was schief gelaufen ist.

  • Die eigentliche Frage, die ich gestellt habe, war: Ist es in der Branche üblich, zu verhindern, dass Unternehmensanwendungen abstürzen? und ich frage nicht nach leerem try / catch . Ist es so, dass Benutzer Anwendungen lieben, die nicht abstürzen, als Anwendungen, die sich unerwartet verhalten? Weil es wirklich darauf ankommt, es entweder zum Absturz zu bringen oder dem Benutzer einen leeren Bildschirm anzuzeigen oder das Verhalten des Benutzers nicht zu bemerken.

  • Ich poste hier ein paar Ausschnitte aus dem echten Code

      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) {
        }
    }
    

Es handelt sich nicht um ein Duplikat der Best Practices für die Behandlung von Android-Ausnahmen . Dort versucht OP, Ausnahmen für einen anderen Zweck als diese Frage abzufangen.


11
Beantworten Sie Ihre Frage nicht, aber schlucken Sie niemals Ausnahmen catch(Exception e){}- dieser Kommentar machte vor der Bearbeitung der Frage Sinn
Scary Wombat


29
Ah, der berüchtigteON ERROR RESUME NEXT
Deduplicator

Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Bhargav Rao

1
Diese Frage brachte mich zum Nachdenken, weil ich den try {} catch (Ausnahme e) {} auch oft benutze, wenn mir die Zeit ausgeht
Raut Darpan

Antworten:


81

Natürlich gibt es immer Ausnahmen von Regeln, aber wenn Sie eine Faustregel benötigen, dann sind Sie richtig; leere Fangblöcke sind "absolut" schlechte Praxis.

Schauen wir uns das genauer an und beginnen wir mit Ihrem konkreten Beispiel:

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

So wird ein Verweis auf etwas erstellt; und wenn das fehlschlägt ... spielt es keine Rolle; weil diese Referenz überhaupt nicht verwendet wird! Der obige Code ist absolut nutzloses Leitungsrauschen . Oder geht die Person, die diesen Code geschrieben hat, zunächst davon aus, dass ein zweiter, ähnlicher Aufruf auf magische Weise keine Ausnahme mehr auslösen würde?!

Vielleicht sollte das so aussehen:

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

Aber was hilft das wieder?! Es gibt Ausnahmen, um Fehlersituationen in Ihrem Code zu kommunizieren bzw. zu verbreiten . Das Ignorieren von Fehlern ist selten eine gute Idee. Tatsächlich kann eine Ausnahme folgendermaßen behandelt werden:

  • Sie geben dem Benutzer Feedback. (wie: "Der eingegebene Wert ist keine Zeichenfolge, versuchen Sie es erneut"); oder sich auf eine komplexere Fehlerbehandlung einzulassen
  • Vielleicht wird das Problem irgendwie erwartet und kann gemildert werden (zum Beispiel durch eine "Standard" -Antwort, wenn eine "Fernrecherche" fehlgeschlagen ist)
  • ...

Lange Rede kurzer Sinn: die Mindeste, was Sie mit einer Ausnahme tun, ist, sie zu protokollieren / zu verfolgen. Wenn Sie später ein Problem debuggen, verstehen Sie "OK, zu diesem Zeitpunkt ist diese Ausnahme aufgetreten".

Und wie andere bereits betont haben: Sie vermeiden es auch, generell nach Ausnahmen zu suchen (je nach Ebene: Es kann gute Gründe geben, Ausnahmen zu fangen und sogar einige Arten von Fehlern auf höchster Ebene, um dies sicherzustellen nichts geht verloren; niemals ).

Zum Schluss zitieren wir Ward Cunningham :

Sie wissen, dass Sie mit sauberem Code arbeiten, wenn sich herausstellt, dass jede Routine, die Sie lesen, ziemlich genau Ihren Erwartungen entspricht. Sie können es als schönen Code bezeichnen, wenn der Code auch den Eindruck erweckt, dass die Sprache für das Problem erstellt wurde.

Lass das einwirken und meditiere darüber. Sauberer Code ist nicht überraschen. Das Beispiel, das Sie uns zeigen, überrascht alle ansehen.

Update bezüglich des Updates, nach dem das OP fragt

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

Gleiche Antwort: Das "überall" zu tun ist auch eine schlechte Praxis. Weil dieser Code auch ist überraschend die Leser.

Obenstehendes:

  • Druckt irgendwo Fehlerinformationen. Es ist überhaupt nicht garantiert, dass dieses "irgendwo" einem vernünftigen ähnelt Ziel . Im Gegenteil. Beispiel: In der Anwendung, mit der ich arbeite, werden solche Aufrufe auf magische Weise in unseren Ablaufverfolgungspuffern angezeigt. Je nach Kontext pumpt unsere Anwendung manchmal Tonnen und Tonnen von Daten in diese Puffer. Lassen Sie diesen Puffer alle paar Sekunden beschneiden. "Nur Druckfehler" bedeutet also oft: "Alle diese Fehlerinformationen einfach verlieren".
  • Dann: Sie versuchen / fangen nicht, weil Sie können . Sie tun es, weil Sie verstehen, was Ihr Code tut. und du weißt: Ich versuche hier besser, das Richtige zu tun (siehe die ersten Teile meiner Antwort noch einmal).

Verwenden Sie also try / catch als "Muster", wie Sie es zeigen. ist wie gesagt: immer noch keine gute idee. Und ja, es verhindert Abstürze; führt aber zu allen Arten von "undefiniertem" Verhalten. Sie wissen, wenn Sie nur eine Ausnahme abfangen, anstatt sie richtig zu behandeln. Sie öffnen eine Dose Würmer; weil Sie in Myriaden führen könnten Folge auf Fehler , die Sie später nicht verstehen. Weil Sie das Ereignis "Grundursache" früher konsumiert haben; druckte es irgendwo; und das irgendwo ist jetzt weg.


1
Was ist, wenn ich einen Stack-Trace drucke? Ich glaube immer noch nicht, dass ich hier versuchen / fangen muss.
Mallaudin

3
Ich muss zugeben, dass ich Ihre Bearbeitung nicht bekomme. Keine wirkliche Idee, was Sie dort tun; oder wo kommst du damit hin?
GhostCat

@mallaudin Im Allgemeinen wird alles nach der Zeile, die das Programm zum Absturz bringt, nicht ausgeführt (obvs), daher ist das Drucken nur Unsinn. In diesem speziellen Fall, dh versuchen Sie + außer, würde zumindest etwas angezeigt und die Ausnahme würde nicht zum Schweigen gebracht.
Peter Badida

2
@GhostCat Das OP sagt zu einem Kommentar in einer anderen Antwort, dass die Ausnahmeblöcke bereits Protokollierungsaufrufe enthalten. Die Frage stellt falsch dar, was wirklich los ist, daher denke ich nicht, dass es hier hilfreich ist, den älteren Entwickler zu beschuldigen, inkompetent zu sein. Ich denke, es ist mehr los als nur das, was uns das OP gibt.
jpmc26

1
@ GhostCat Es geht nicht um Repo, ich habe nur gemerkt, dass mein Beispiel schlecht ist. Alle dachten, ich
frage

15

Aus der Android-Dokumentation :

Nennen wir es als -

Keine generische Ausnahme abfangen

Es kann auch verlockend sein, beim Abfangen von Ausnahmen faul zu sein und so etwas zu tun:

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!
}

In fast allen Fällen ist es unangemessen, generisch Exceptionoder Throwable zu fangen (vorzugsweise nicht Throwable, da es Fehlerausnahmen enthält). Dies ist sehr gefährlich, da Ausnahmen, die Sie nie erwartet haben (einschließlich RuntimeExceptionsähnlicher ClassCastException), bei der Fehlerbehandlung auf Anwendungsebene abgefangen werden.

Dadurch werden Exceptiondie Fehlerbehandlungseigenschaften Ihres Codes verdeckt. Wenn also jemand einen neuen Typ in den von Ihnen aufgerufenen Code einfügt, hilft Ihnen der Compiler nicht zu erkennen, dass Sie den Fehler anders behandeln müssen .

Alternativen zum Fangen von generischen Ausnahmen:

  • Fangen Sie jede Ausnahme nach einem einzigen Versuch separat als separate Fangblöcke ab. Dies kann umständlich sein, ist jedoch dem Abfangen aller Ausnahmen vorzuziehen.
    Vom Autor bearbeiten: Dies ist meine Wahl. Achten Sie darauf, dass Sie nicht zu viel Code in den Catch-Blöcken wiederholen. Wenn Sie Java 7 oder höher verwenden, verwenden Sie Multi-Catch, um zu vermeiden, dass der gleiche Catch-Block wiederholt wird.
  • Überarbeiten Sie Ihren Code, um eine detailliertere Fehlerbehandlung zu erhalten mit mehreren Versuchsblöcken zu erhalten. Teilen Sie die E / A von der Analyse auf und behandeln Sie Fehler jeweils separat.
  • Wirf die Ausnahme erneut . Oft müssen Sie die Ausnahme auf dieser Ebene sowieso nicht abfangen, lassen Sie sie einfach von der Methode auslösen.

In den meisten Fällen sollten Sie verschiedene Arten von Ausnahmen nicht auf die gleiche Weise behandeln.

Formatierung / Absatz leicht geändert von der Quelle für diese Antwort.

PS Hab keine Angst vor Ausnahmen !! Sie sind Freunde!!!


1
Wenn Sie jede Ausnahme einzeln abfangen, stellen Sie sicher, dass Sie die Ausführung nicht in einem unsicheren Zustand fortsetzen (vermeiden Sie Dinge wie Object a; try { a = thing(); } catch (Exception e) {...} try { a.action(); } catch (Exception e) {...}))
njzk2

Um fair zu sein, Exceptionkönnte das Fangen von Generika als Teil eines "Log-before-Crashing" -Systems nützlich sein, obwohl es in diesem Fall neu geworfen werden sollte.
Justin Time - Wiedereinsetzung Monica

9

Ich würde dies als Kommentar zu einer anderen Antwort setzen, aber dafür habe ich noch keinen Ruf.

Sie sagen zu Recht, dass es sich um eine schlechte Praxis handelt. In der Tat zeigt das, was Sie veröffentlicht haben, verschiedene Arten von schlechten Praktiken in Bezug auf Ausnahmen.

  1. Fehlende Fehlerbehandlung
  2. Generischer Fang
  3. Keine absichtlichen Ausnahmen
  4. Decke versuchen / fangen

Ich werde versuchen, all dies anhand dieses Beispiels zu erklären.

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

Dies kann auf verschiedene Arten fehlschlagen, die unterschiedlich gehandhabt werden sollten.

  1. Die Felder werden nicht ausgefüllt, so dass dem Benutzer ein leerer Bildschirm angezeigt wird und dann ... was? Nichts - mangelnde Fehlerbehandlung.
  2. Es gibt keinen Unterschied zwischen verschiedenen Arten von Fehlern, z. B. Internetproblemen oder Problemen mit dem Server selbst (Ausfall, fehlerhafte Anforderung, beschädigte Übertragung, ...) - Allgemeiner Fang.
  3. Sie können Ausnahmen nicht für Ihre eigenen Zwecke verwenden, da das aktuelle System dies stört. - Keine absichtlichen Ausnahmen
  4. Unnötige und unerwartete Fehler (z. B. null.equals (...)) können dazu führen, dass wesentlicher Code nicht ausgeführt wird. - Decke versuchen / fangen

Lösungen

(1) Zuallererst ist es keine gute Sache, lautlos zu versagen. Wenn ein Fehler auftritt, funktioniert die App nicht. Stattdessen sollte versucht werden, das Problem zu beheben, oder eine Warnung angezeigt werden, z. B. "Benutzerdaten konnten nicht geladen werden, möglicherweise sind Sie nicht mit dem Internet verbunden?". Wenn die App nicht das tut, was sie soll, ist das für einen Benutzer viel frustrierender, als wenn sie sich einfach selbst schließt.

(4) Wenn der Benutzer unvollständig ist, z. B. das Land nicht bekannt ist und null zurückgibt. Die equals-Methode erstellt eine NullPointerException. Wenn diese NPE wie oben geworfen und abgefangen wird, wird die Methode fillFields (Benutzer) nicht aufgerufen, obwohl sie weiterhin problemlos ausgeführt werden kann. Sie können dies verhindern, indem Sie Nullprüfungen einschließen, die Ausführungsreihenfolge ändern oder den Try / Catch-Bereich anpassen. (Oder Sie könnten die Codierung wie folgt speichern: "us" .equals (user.getCountry ()), aber ich musste ein Beispiel angeben). Natürlich verhindert jede andere Ausnahme auch die Ausführung von fillFields (), aber wenn kein Benutzer vorhanden ist, möchten Sie wahrscheinlich nicht, dass es trotzdem ausgeführt wird.

(1, 2, 3) Beim Laden aus dem Web werden häufig verschiedene Ausnahmen ausgelöst, von der IOException über die Ausnahme HttpMessageNotReadable bis hin zur Rückkehr. Möglicherweise ist der Benutzer nicht mit dem Internet verbunden, möglicherweise wurde ein Backend-Server geändert oder er ist ausgefallen, aber Sie wissen es nicht, weil Sie abfangen (Ausnahme). Stattdessen sollten Sie bestimmte Ausnahmen abfangen. Sie können sogar mehrere davon so fangen

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();
}

Ich hoffe das erklärt es.

Zumindest als schnelle Lösung können Sie mit Ausnahme eines Ereignisses ein Ereignis an Ihr Backend senden. Zum Beispiel durch Firebase oder Crashlytics. Auf diese Weise können Sie zumindest Dinge wie (hey, die Hauptaktivität wird für 80% unserer Benutzer aufgrund eines Problems wie (4) nicht geladen.


8

Es ist definitiv eine schlechte Programmierpraxis.

Aus dem aktuellen Szenario, wenn es Hunderte von gibt try catch davon gibt, wissen Sie nicht einmal, wo die Ausnahme auftritt, ohne die Anwendung zu debuggen. Dies ist ein Albtraum, wenn sich Ihre Anwendung in einer Produktionsumgebung befindet.

Sie können jedoch einen Logger einbinden, damit Sie wissen, wann eine Ausnahme ausgelöst wird (und warum). Es wird Ihren normalen Workflow nicht ändern.

...
try {
    View view = findViewById(R.id.toolbar);
}catch(Exception e){
    logger.log(Level.SEVERE, "an exception was thrown", e);
}
...

7

Das ist schlechte Praxis. Andere Antworten haben das gesagt, aber ich denke, es ist wichtig, zurückzutreten und zu verstehen, warum wir überhaupt Ausnahmen haben.

Jede Funktion hat eine Nachbedingung - eine Reihe von Dingen, die alle wahr sein müssen, nachdem diese Funktion ausgeführt wurde. Beispielsweise hat eine Funktion, die aus einer Datei liest, die Post-Bedingung, dass die Daten in der Datei von der Festplatte gelesen und zurückgegeben werden. Eine Ausnahme wird dann ausgelöst, wenn eine Funktion eine ihrer Nachbedingungen nicht erfüllen konnte.

Indem Sie eine Ausnahme von einer Funktion ignorieren (oder sie sogar effektiv ignorieren, indem Sie einfach die Ausnahme protokollieren), sagen Sie, dass Sie mit dieser Funktion einverstanden sind, wenn Sie nicht die gesamte Arbeit erledigen, für die sie sich bereit erklärt hat. Dies scheint unwahrscheinlich - wenn eine Funktion nicht korrekt ausgeführt wird, gibt es keine Garantie dafür, dass das Folgende überhaupt ausgeführt wird. Und wenn der Rest Ihres Codes einwandfrei funktioniert, unabhängig davon, ob eine bestimmte Funktion vollständig ausgeführt wird oder nicht, fragt man sich, warum Sie diese Funktion überhaupt haben.

[Jetzt gibt es bestimmte Fälle, in denen leere catches in Ordnung sind. Zum Beispiel ist die Protokollierung etwas, das Sie möglicherweise rechtfertigen, wenn Sie einen leeren Fang einschließen. Ihre Anwendung wird wahrscheinlich auch dann einwandfrei ausgeführt, wenn ein Teil der Protokollierung nicht geschrieben werden kann. Aber das sind Sonderfälle, bei denen man wirklich hart arbeiten muss, um sie in einer normalen App zu finden.]

Der Punkt ist also, dass dies eine schlechte Praxis ist, da Ihre App dadurch nicht weiter ausgeführt wird (die angebliche Rechtfertigung für diesen Stil). Vielleicht hat das Betriebssystem es technisch nicht getötet. Es ist jedoch unwahrscheinlich, dass die App nach einfachem Ignorieren einer Ausnahme noch ordnungsgemäß ausgeführt wird. Und im schlimmsten Fall kann es tatsächlich Schaden anrichten (z. B. Beschädigung von Benutzerdateien usw.).


3

Dies ist aus mehreren Gründen schlecht:

  1. Was machst du das? findViewById eine Ausnahme auslöst? Beheben Sie das (und sagen Sie mir, weil ich das noch nie gesehen habe), anstatt es zu fangen.
  2. Nicht fangen Exception Sie wenn Sie eine bestimmte Art von Ausnahme könnten.
  3. Es gibt diese Überzeugung, dass gute Apps nicht abstürzen. Das ist nicht wahr. Eine gute App stürzt ab, wenn es sein muss.

Wenn eine App in einen schlechten Zustand gerät, ist es viel besser, wenn sie abstürzt, als wenn sie in ihrem unbrauchbaren Zustand tuckert. Wenn man eine NPE sieht, sollte man nicht einfach einen Null-Check machen und weggehen. Der bessere Ansatz besteht darin, herauszufinden, warum etwas null ist, und entweder zu verhindern, dass es null ist, oder (wenn null ein gültiger und erwarteter Zustand ist) nach null zu suchen. Sie müssen jedoch verstehen, warum das Problem überhaupt auftritt.


2

Ich habe in den letzten 4-5 Jahren Android-Apps entwickelt und nie einen Try-Catch für die Ansichtsinitialisierung verwendet.

Wenn es eine Symbolleiste ist, machen Sie das so

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

Beispiel: - Um eine Textansicht aus einer Ansicht abzurufen (Fragment / Dialog / eine benutzerdefinierte Ansicht)

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

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

an Stelle von

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

Ein Ansichtsobjekt hat im Vergleich zu seinem tatsächlichen Ansichtstyp eine minimale Reichweite.

Hinweis: - Möglicherweise ist es abgestürzt, weil die Ansicht geladen wurde. Das Hinzufügen von Try Catch ist jedoch eine schlechte Praxis.


In vielen Fällen ist das Casting der Ansicht nicht erforderlich. Es gibt einige Methoden, die Sie verwenden Viewkönnen und die bereits nützlich sein können (wie setVisibility()), ohne dass Sie genau angeben, welche Klasse verwendet wird. (Zum Beispiel im Fall eines Layouts, das von Zeit zu Zeit geändert werden kann)
njzk2

1

Ja, try / catch wird verwendet, um einen Absturz der App zu verhindern, aber Sie benötigen try / catch sicherlich nicht, um eine Ansicht aus XML abzurufen, wie in Ihrer Frage dargestellt.

try / catch wird im Allgemeinen verwendet, wenn Sie eine http-Anfrage stellen, einen String in eine URL analysieren, URL-Verbindungen erstellen usw. und sicherstellen, dass die Stapelverfolgung gedruckt wird. Wenn Sie es nicht drucken, macht es wenig Sinn, es mit try / catch zu umgeben.


1

Wie bereits erwähnt, sollten allgemeine Ausnahmen nicht oder nur in wenigen Fällen abgefangen werden zentralen Stellen (normalerweise im Framework- / Infrastrukturcode, nicht im Anwendungscode). Wenn allgemeine Ausnahmen abgefangen und protokolliert werden, sollte die Anwendung anschließend heruntergefahren werden, oder zumindest sollte der Benutzer darüber informiert werden, dass sich die Anwendung möglicherweise in einem instabilen Zustand befindet und Daten beschädigt werden können (wenn der Benutzer die Ausführung fortsetzt). Denn dies kann passieren, wenn Sie alle Arten von Ausnahmen abfangen (nicht genügend Speicher, um nur eine zu nennen) und die App in einem undefinierten Zustand belassen.

IMHO ist es schlimmer, Ausnahmen zu schlucken und Datenintegrität, Datenverlust oder einfach das Verlassen der App in einem undefinierten Zustand zu riskieren, als die App abstürzen zu lassen und der Benutzer weiß, dass etwas schief gelaufen ist und kann es erneut versuchen. Dies führt auch zu besseren gemeldeten Problemen (mehr an der Wurzel des Problems), wahrscheinlich weniger unterschiedlichen Symptomen, als wenn Ihre Benutzer anfangen, alle Arten von Problemen zu melden, die vom undefinierten Anwendungsstatus herrühren.

Beginnen Sie nach einer zentralen Ausnahmebehandlung / Protokollierung / Berichterstellung und einem kontrollierten Herunterfahren mit dem Umschreiben der Ausnahmebehandlung, um lokale Ausnahmen so spezifisch wie möglich zu erfassen. Versuchen Sie, den try {} -Block so kurz wie möglich zu halten.


1

Lassen Sie mich meinen Standpunkt hinzufügen, als ein Mann, der seit mehr als einem Jahrzehnt in der mobilen Entwicklungsbranche von Unternehmen tätig ist. Zunächst einige allgemeine Tipps zu Ausnahmen, von denen die meisten in den obigen Antworten enthalten sind:

  • Ausnahmen sollten für außergewöhnliche, unerwartete oder unkontrollierte Situationen verwendet werden, nicht regelmäßig im gesamten Code.
  • Ein Programmierer muss die Teile des Codes kennen, die Ausnahmen auslösen können, und versuchen, sie abzufangen, damit der Rest des Codes so sauber wie möglich bleibt.
  • Ausnahmen sollten in der Regel nicht stillgelegt werden.

Wenn Sie jetzt keine App für sich selbst entwickeln, sondern für ein Unternehmen oder eine Firma, müssen Sie häufig zusätzliche Anforderungen zu diesem Thema stellen:

  • "App-Abstürze zeigen ein schlechtes Image des Unternehmens, daher sind sie nicht akzeptabel." Dann sollte eine sorgfältige Entwicklung durchgeführt werden, und es kann eine Option sein, selbst unwahrscheinliche Ausnahmen zu erwischen. In diesem Fall muss dies selektiv erfolgen und in angemessenen Grenzen gehalten werden. Beachten Sie, dass es bei der Entwicklung nicht nur um Codezeilen geht. In diesen Fällen ist beispielsweise ein intensiver Testprozess von entscheidender Bedeutung. Unerwartetes Verhalten in einer Unternehmens-App ist jedoch schlimmer als ein Absturz. Wenn Sie also eine Ausnahme in Ihrer App feststellen, müssen Sie wissen, was zu tun ist, was anzuzeigen ist und wie sich die App als Nächstes verhält. Wenn Sie das nicht kontrollieren können, lassen Sie die App besser abstürzen.
  • "Protokolle und Stapelspuren können vertrauliche Informationen an die Konsole senden. Diese können für einen Angreifer verwendet werden, daher können sie aus Sicherheitsgründen nicht in einer Produktionsumgebung verwendet werden." Diese Anforderung steht im Widerspruch zu der allgemeinen Regel, dass Entwickler keine stillen Ausnahmen schreiben müssen, sodass Sie einen Weg dafür finden müssen. Zum Beispiel könnte Ihre App die Umgebung steuern, sodass sie Protokolle und Stack-Traces in Nicht-Produktionsumgebungen verwendet, während Cloud-basierte Tools wie Bugsense, Crashlitics oder ähnliches für Produktionsumgebungen verwendet werden.

Die kurze Antwort lautet also, dass der Code, den Sie gefunden haben, kein Beispiel für eine gute Praxis ist, da die Wartung schwierig und kostspielig ist, ohne die Qualität der App zu verbessern.


1

Eine andere Perspektive: Als jemand, der täglich Unternehmenssoftware schreibt, möchte ich, dass eine App abstürzt , wenn sie einen nicht behebbaren Fehler aufweist . Absturz ist wünschenswert. Wenn es abstürzt, wird es protokolliert. Wenn es in kurzer Zeit mehr als ein paar Mal abstürzt, erhalte ich eine E-Mail mit dem Hinweis, dass die App abstürzt, und ich kann überprüfen, ob unsere App und alle von uns genutzten Webdienste noch funktionieren.

Also die Frage:

Ist

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

gute Übung? Nein! Hier sind einige Punkte:

  1. Das Wichtigste: Dies ist eine schlechte Kundenerfahrung. Woher soll ich wissen, wenn etwas Schlimmes passiert? Meine Kunden versuchen, meine App zu verwenden, und nichts funktioniert. Sie können ihr Bankkonto nicht überprüfen, ihre Rechnungen nicht bezahlen, was auch immer meine App tut. Meine App ist völlig nutzlos, aber hey, zumindest ist sie nicht abgestürzt! (Ein Teil von mir glaubt, dass dieser "ältere" Entwickler Brownie-Punkte für niedrige Crash-Zahlen bekommt, also spielen sie das System.)

  2. Wenn ich entwickle und schlechten Code schreibe, wenn ich nur alle Ausnahmen auf der obersten Ebene abfange und verschlucke, habe ich keine Protokollierung. Ich habe nichts in meiner Konsole und meine App schlägt lautlos fehl. Soweit ich das beurteilen kann, scheint alles in Ordnung zu sein. Also habe ich den Code festgeschrieben ... Es stellte sich heraus, dass mein DAO-Objekt die ganze Zeit über null war und die Zahlungen des Kunden in der Datenbank nie aktualisiert wurden. Hoppla! Aber meine App ist nicht abgestürzt, das ist also ein Plus.

  3. Nehmen wir an, ich war damit einverstanden, jede Ausnahme zu fangen und zu schlucken. Es ist extrem einfach , einen benutzerdefinierten Ausnahmebehandler in Android zu schreiben. Wenn Sie wirklich nur haben jede Ausnahme zu fangen, können Sie es an einem Ort tun und nicht Pfeffer try/catchganzen Code - Basis.

Einige der Entwickler, mit denen ich in der Vergangenheit zusammengearbeitet habe, haben den Absturz für schlecht gehalten.

Ich muss ihnen versichern, dass unsere App abstürzen soll. Nein, eine instabile App ist nicht in Ordnung, aber ein Absturz bedeutet, dass wir etwas falsch gemacht haben und es beheben müssen. Je schneller es abstürzt, je früher wir es finden, desto einfacher ist es zu beheben. Die einzige andere Option, die ich mir vorstellen kann, besteht darin, dem Benutzer zu erlauben, in einer unterbrochenen Sitzung fortzufahren, was ich mit dem Verärgern meiner Benutzerbasis gleichsetze.


0

Es ist eine schlechte Praxis catch(Exception e){} weil Sie den Fehler im Wesentlichen ignorieren. Was Sie wahrscheinlich tun möchten, ist eher so etwas wie:

try {
    //run code that could crash here
} catch (Exception e) {
    System.out.println(e.getMessage());
}

0

Wir verwenden so ziemlich dieselbe Logik. Verwendentry-catch diese , um zu verhindern, dass Produktions-Apps abstürzen.

Ausnahmen sollten NIE sein ignoriert werden. Es ist eine schlechte Codierungspraxis. Die Leute, die den Code pflegen, werden es wirklich schwer haben, den Teil des Codes zu lokalisieren, der die Ausnahme ausgelöst hat, wenn sie nicht protokolliert sind.

Wir verwenden Crashlytics, um die Ausnahmen zu protokollieren. Der Code stürzt nicht ab (einige Funktionen werden jedoch unterbrochen). Sie erhalten jedoch das Ausnahmeprotokoll im Dashboard von Fabric/Crashlytics. Sie können sich diese Protokolle ansehen und die Ausnahmen beheben.

try {
    codeThatCouldRaiseError();
} catch (Exception e) {
    e.printStackTrace();
    Crashlytics.logException(e);
}

Ja. Das machen die Leute hier, aber ich bin damit nicht einverstanden. Deshalb habe ich die Frage gestellt. Können Sie sich etwas Logischeres einfallen lassen?
Mallaudin

4
@mallaudin Veröffentlichen Sie keinen Beispielcode, der den Code, nach dem Sie fragen, falsch darstellt. Es kann die Antwort, die Sie erhalten, drastisch ändern.
jpmc26

@ jpmc26 ja. Ich habe das in Antworten gesehen.
Mallaudin

0

Obwohl ich den anderen Antworten zustimme, habe ich wiederholt einen Umstand festgestellt, bei dem dieses Motiv nur geringfügig tolerierbar ist. Angenommen, jemand hat ein bisschen Code für eine Klasse wie folgt geschrieben:

private int foo=0;

    . . .

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

Unter diesen Umständen kann die Methode 'getFoo ()' nicht fehlschlagen. Es wird immer ein legitimer Wert des privaten Felds 'foo' zurückgegeben. Dennoch hat jemand - wahrscheinlich aus pedantischen Gründen - entschieden, dass diese Methode als potenziell auslösend deklariert werden sollte. Wenn Sie dann versuchen, diese Methode in einem Kontext aufzurufen - z. B. einem Ereignishandler -, in dem keine Ausnahme ausgelöst werden kann, müssen Sie dieses Konstrukt grundsätzlich verwenden (selbst dann stimme ich zu, dass man zumindest die Ausnahme nur protokollieren sollte falls) . Wann immer ich dies tun muss, füge ich neben der 'catch'-Klausel mindestens einen großen, fetten Kommentar hinzu: "DAS KANN NICHT AUFTRETEN".

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.