it-swarm.com.de

Ist es empfehlenswert, eine aktivierte Ausnahme abzufangen und eine RuntimeException auszulösen?

Ich habe den Code eines Kollegen gelesen und festgestellt, dass er häufig verschiedene Ausnahmen abfängt und stattdessen immer eine 'RuntimeException' auslöst. Ich habe immer gedacht, dass dies eine sehr schlechte Praxis ist. Liege ich falsch?

73

Ich kenne nicht genug Kontext, um zu wissen, ob Ihr Kollege etwas falsch macht oder nicht, deshalb werde ich allgemein darüber streiten.

Ich denke nicht, dass es immer eine falsche Praxis ist, überprüfte Ausnahmen in eine Art Laufzeitausnahme umzuwandeln. Geprüfte Ausnahmen sind oft missbraucht und missbraucht von Entwicklern.

Es ist sehr einfach, geprüfte Ausnahmen zu verwenden, wenn sie nicht verwendet werden sollen (nicht behebbare Bedingungen oder sogar Kontrollfluss). Insbesondere wenn eine aktivierte Ausnahme für Bedingungen verwendet wird, von denen der Anrufer keine Wiederherstellung durchführen kann, halte ich es für gerechtfertigt, diese Ausnahme in eine Laufzeitausnahme mit einer hilfreichen Nachricht/einem hilfreichen Status umzuwandeln. Leider neigen sie in vielen Fällen, wenn sie mit einem nicht behebbaren Zustand konfrontiert sind, dazu, einen leeren Fangblock zu haben, was eines der schlimmsten Dinge ist, die Sie tun können. Das Debuggen eines solchen Problems ist eines der größten Probleme, denen Entwickler begegnen können.

Wenn Sie also der Meinung sind, dass es sich um eine wiederherstellbare Bedingung handelt, sollte diese entsprechend behandelt und die Ausnahme nicht in eine Laufzeitausnahme umgewandelt werden. Wenn eine aktivierte Ausnahme für nicht behebbare Bedingungen verwendet wird, ist es gerechtfertigt, sie in eine Laufzeitausnahme umzuwandeln..

56
c_maker

Es kann GUT sein . Bitte lesen Sie dieser Artikel auf onjava.com :

In den meisten Fällen kann Client-Code nichts gegen SQLExceptions unternehmen. Zögern Sie nicht, sie in ungeprüfte Ausnahmen umzuwandeln. Betrachten Sie den folgenden Code:

public void dataAccessCode(){
  try{
      ..some code that throws SQLException
  }catch(SQLException ex){
      ex.printStacktrace();
  }
} 

Dieser catch-Block unterdrückt nur die Ausnahme und führt nichts aus. Die Rechtfertigung ist, dass mein Client nichts gegen eine SQLException unternehmen kann. Wie wäre es damit, wie folgt damit umzugehen?

public void dataAccessCode(){
   try{
       ..some code that throws SQLException
   }catch(SQLException ex){
       throw new RuntimeException(ex);
   }
} 

Dadurch wird SQLException in RuntimeException konvertiert. Wenn SQLException auftritt, löst die catch-Klausel eine neue RuntimeException aus. Der Ausführungsthread wird angehalten und die Ausnahme wird gemeldet. Ich beschädige meine Geschäftsobjektschicht jedoch nicht durch unnötige Ausnahmebehandlung, zumal sie nichts gegen eine SQLException unternehmen kann. Wenn mein Fang die Grundausnahmeursache benötigt, kann ich die Methode getCause () verwenden, die ab JDK1.4 in allen Ausnahmeklassen verfügbar ist.

Es hilft nicht, geprüfte Ausnahmen auszulösen und sich nicht davon erholen zu können.

Einige Leute denken sogar, dass geprüfte Ausnahmen überhaupt nicht verwendet werden sollten. Siehe http://www.ibm.com/developerworks/Java/library/j-jtp05254/index.html

Kürzlich haben mehrere angesehene Experten, darunter Bruce Eckel und Rod Johnson, öffentlich erklärt, dass sie, obwohl sie der orthodoxen Position zu geprüften Ausnahmen zunächst vollständig zustimmten, zu dem Schluss gekommen sind, dass die ausschließliche Verwendung geprüfter Ausnahmen keine so gute Idee ist wie sie erschien zuerst, und dass geprüfte Ausnahmen für viele große Projekte zu einer bedeutenden Problemquelle geworden sind. Eckel ist extremer und schlägt vor, alle Ausnahmen zu deaktivieren. Johnsons Ansicht ist konservativer, deutet jedoch immer noch darauf hin, dass die orthodoxe Präferenz für geprüfte Ausnahmen übertrieben ist. (Es ist erwähnenswert, dass die Architekten von C #, die mit ziemlicher Sicherheit viel Erfahrung mit der Verwendung von Java Technologie) hatten, sich dafür entschieden haben, geprüfte Ausnahmen aus dem Sprachdesign wegzulassen, wodurch alle Ausnahmen ungeprüfte Ausnahmen machten , lassen Sie Raum für eine spätere Implementierung überprüfter Ausnahmen.)

Auch vom selben Link:

Die Entscheidung, ungeprüfte Ausnahmen zu verwenden, ist kompliziert und es ist klar, dass es keine offensichtliche Antwort gibt. Der Sun-Rat ist, sie für nichts zu verwenden, der C # -Ansatz (dem Eckel und andere zustimmen) ist, sie für alles zu verwenden. Andere sagen: "Es gibt einen Mittelweg."

42
mrmuggles

Nein, du liegst nicht falsch. Seine Praxis ist äußerst fehlgeleitet. Sie sollten eine Ausnahme auslösen, die das Problem erfasst, das sie verursacht hat. RunTimeException ist breit und weitreichend. Es sollte eine NullPointerException, ArgumentException usw. sein. Was auch immer genau beschreibt, was schief gelaufen ist. Dies bietet die Möglichkeit, Probleme, die Sie behandeln sollten, zu unterscheiden und das Programm überleben zu lassen, gegenüber Fehlern, bei denen es sich um ein Szenario "Nicht weitergeben" handeln sollte. Was er tut, ist nur geringfügig besser als "On Error Resume Next", es sei denn, in den Informationen in der Frage fehlt etwas.

13
Rig

Es hängt davon ab, ob.

Diese Praxis kann sogar weise sein. Es gibt viele Situationen (zum Beispiel in der Webentwicklung), in denen Sie im Falle einer Ausnahme nichts tun können (weil Sie beispielsweise keine inkonsistente Datenbank aus Ihrem Code reparieren können :-), nur Entwickler können dies tun). In diesen Situationen ist es ratsam, die ausgelöste Ausnahme in eine Laufzeitausnahme zu verpacken und erneut zu werfen. Dann können Sie alle diese Ausnahmen in einer Ausnahmebehandlungsschicht abfangen, den Fehler protokollieren und dem Benutzer einen netten lokalisierten Fehlercode + eine Meldung anzeigen.

Andererseits Wenn die Ausnahme keine Laufzeit ist (aktiviert ist), gibt der Entwickler der API an, dass diese Ausnahme auflösbar ist und repariert werden sollte. Wenn es möglich ist, sollten Sie es auf jeden Fall tun.

Die andere Lösung könnte darin bestehen, diese aktivierte Ausnahme erneut in die aufrufende Ebene zu werfen. Wenn Sie sie jedoch nicht lösen konnten, wo die Ausnahme aufgetreten ist, können Sie sie wahrscheinlich auch hier nicht lösen ...

8
malejpavouk

Ich würde gerne Kommentare dazu erhalten, aber ich finde, dass es Zeiten gibt, in denen dies nicht unbedingt eine schlechte Praxis ist. (Oder schrecklich schlecht). Aber vielleicht irre ich mich.

Oft löst eine von Ihnen verwendete API eine Ausnahme aus, die Sie sich nicht vorstellen können, tatsächlich in Ihrem speziellen Anwendungsfall ausgelöst zu werden. In diesem Fall scheint es vollkommen in Ordnung zu sein, eine RuntimeException mit der abgefangenen Ausnahme als Ursache auszulösen. Wenn diese Ausnahme ausgelöst wird, ist dies wahrscheinlich die Ursache für Programmierfehler und liegt nicht innerhalb der Grenzen für eine korrekte Spezifikation.

Angenommen, die RuntimeException wird später nicht abgefangen und ignoriert, ist sie nicht annähernd in der Nähe eines OnErrorResumeNext.

Der OnErrorResumeNext tritt auf, wenn jemand eine Ausnahme abfängt und sie einfach ignoriert oder einfach ausdruckt. Dies ist in fast allen Fällen eine schrecklich schlechte Praxis.

5
user606723

TL; DR

Prämisse

  • Laufzeitausnahmen sollten ausgelöst werden, wenn der Fehler nicht behebbar ist: Wenn der Fehler im Code enthalten ist und nicht vom externen Status abhängt (daher würde die Wiederherstellung den Code korrigieren).
  • Überprüfte Ausnahmen sollten ausgelöst werden, wenn der Code korrekt ist, der externe Status jedoch nicht wie erwartet ist: Keine Netzwerkverbindung, Datei nicht gefunden oder beschädigt usw.

Fazit

Wir können eine aktivierte Ausnahme als Laufzeitausnahme erneut auslösen, wenn der Propagierungs- oder Schnittstellencode davon ausgeht, dass die zugrunde liegende Implementierung vom externen Status abhängt, wenn dies eindeutig nicht der Fall ist.


In diesem Abschnitt wird das Thema erläutert, wann eine der Ausnahmen ausgelöst werden sollte. Sie können zum nächsten horizontalen Balken springen, wenn Sie nur eine detailliertere Erklärung für die Schlussfolgerung lesen möchten.

Wann ist es angemessen, eine Laufzeitausnahme auszulösen? Sie lösen eine Laufzeitausnahme aus, wenn klar ist, dass der Code falsch ist und die Wiederherstellung durch Ändern des Codes angemessen ist.

Beispielsweise ist es angebracht, eine Laufzeitausnahme für Folgendes auszulösen:

float nan = 1/0;

Dies löst eine Laufzeitausnahme durch Null aus. Dies ist angemessen, da der Code fehlerhaft ist.

Oder hier ist zum Beispiel ein Teil des Konstruktors von HashMap:

public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                loadFactor);
    // more irrelevant code...
}

Um die anfängliche Kapazität oder den Auslastungsfaktor festzulegen, müssen Sie den Code bearbeiten, um sicherzustellen, dass die richtigen Werte übergeben werden. Dies hängt nicht davon ab, ob ein weit entfernter Server aktiv ist, vom aktuellen Status der Festplatte. eine Datei oder ein anderes Programm. Dieser Konstruktor, der mit ungültigen Argumenten aufgerufen wird, hängt von der Richtigkeit des aufrufenden Codes ab, sei es eine falsche Berechnung, die zu ungültigen Parametern oder einem unangemessenen Ablauf führte, bei dem ein Fehler übersehen wurde.

Wann ist es angebracht, eine aktivierte Ausnahme auszulösen? Sie lösen eine aktivierte Ausnahme aus, wenn das Problem wiederhergestellt werden kann, ohne den Code zu ändern. Oder anders ausgedrückt: Sie lösen eine aktivierte Ausnahme aus, wenn der Fehler mit dem Status zusammenhängt, während der Code korrekt ist.

Jetzt kann das Wort "erholen" hier schwierig sein. Dies könnte bedeuten, dass Sie einen anderen Weg finden, um das Ziel zu erreichen: Wenn der Server beispielsweise nicht antwortet, sollten Sie den nächsten Server ausprobieren. Wenn diese Art der Wiederherstellung für Ihren Fall möglich ist, ist das großartig, aber das ist nicht das einzige, was Wiederherstellung bedeutet. Bei der Wiederherstellung kann dem Benutzer einfach ein Fehlerdialog angezeigt werden, in dem erklärt wird, was passiert ist, oder wenn es sich um eine Serveranwendung handelt, kann dies der Fall sein Senden einer E-Mail an den Administrator oder Protokollieren des Fehlers angemessen und präzise.

Nehmen wir das Beispiel, das in der Antwort von mrmuggles erwähnt wurde:

public void dataAccessCode(){
   try{
       ..some code that throws SQLException
   }catch(SQLException ex){
       throw new RuntimeException(ex);
   }
}

Dies ist nicht die richtige Methode, um die aktivierte Ausnahme zu behandeln. Die bloße Unfähigkeit, die Ausnahme im Bereich dieser Methode zu behandeln, bedeutet nicht, dass die App abstürzen sollte. Stattdessen ist es angebracht, es wie folgt in einen höheren Bereich zu übertragen:

public Data dataAccessCode() throws SQLException {
    // some code that communicates with the database
}

Was die Möglichkeit der Wiederherstellung durch den Anrufer ermöglicht:

public void loadDataAndShowUi() {
    try {
        Data data = dataAccessCode();
        showUiForData(data);
    } catch(SQLException e) {
        // Recover by showing an error alert dialog
        showCantLoadDataErrorDialog();
    }
}

Überprüfte Ausnahmen sind ein statisches Analysetool. Sie machen einem Programmierer klar, was bei einem bestimmten Aufruf schief gehen kann, ohne dass er die Implementierung lernen oder einen Versuch und Irrtum durchlaufen muss. Dies macht es einfach sicherzustellen, dass keine Teile des Fehlerflusses ignoriert werden. Das erneute Auslösen einer aktivierten Ausnahme als Laufzeitausnahme wirkt dieser arbeitssparenden statischen Analysefunktion entgegen.

Es ist auch erwähnenswert, dass die aufrufende Schicht einen besseren Kontext des größeren Schemas der Dinge hat, wie oben gezeigt wurde. Es kann viele Ursachen dafür geben, dass dataAccessCode aufgerufen wird. Der spezifische Grund für den Aufruf ist nur für den Anrufer sichtbar. Auf diese Weise kann er bei einem Fehler eine bessere Entscheidung über die korrekte Wiederherstellung treffen.

Nachdem wir diese Unterscheidung klargestellt haben, können wir ableiten, wann es in Ordnung ist, eine aktivierte Ausnahme als Laufzeitausnahme erneut auszulösen.


Wann ist es angesichts der obigen Ausführungen angebracht, eine aktivierte Ausnahme als RuntimeException erneut auszulösen? Wenn der von Ihnen verwendete Code eine Abhängigkeit vom externen Status annimmt, Sie jedoch eindeutig behaupten können, dass er nicht vom externen Status abhängt.

Folgendes berücksichtigen:

StringReader sr = new StringReader("{\"test\":\"test\"}");
try {
    doesSomethingWithReader(sr); // calls #read, so propagates IOException
} catch (IOException e) {
    throw new IllegalStateException(e);
}

In diesem Beispiel verbreitet der Code IOException, da die API von Reader für den Zugriff auf den externen Status ausgelegt ist. Wir wissen jedoch, dass die Implementierung von StringReader nicht auf den externen Status zugreift. In diesem Bereich, in dem wir mit Sicherheit behaupten können, dass die an dem Aufruf beteiligten Teile nicht auf IO oder einen anderen externen Status zugreifen), können wir die Ausnahme sicher als Laufzeitausnahme erneut auslösen, ohne die Kollegen zu überraschen sind sich unserer Implementierung nicht bewusst (und gehen möglicherweise davon aus, dass E/A-Zugriffscode ein IOException auslöst).


Der Grund für die strikte Überprüfung externer zustandsabhängiger Ausnahmen ist, dass sie nicht deterministisch sind (im Gegensatz zu logisch abhängigen Ausnahmen, die jedes Mal für a vorhersehbar reproduziert werden Version des Codes). Wenn Sie beispielsweise versuchen, durch 0 zu teilen, wird immer eine Ausnahme erzeugt. Wenn Sie nicht durch 0 teilen, wird niemals eine Ausnahme erzeugt, und Sie müssen diesen Ausnahmefall nicht behandeln, da dies niemals passieren wird. Wenn Sie auf eine Datei zugreifen, bedeutet ein einmaliger Erfolg jedoch nicht, dass Sie das nächste Mal erfolgreich sind. Der Benutzer hat möglicherweise die Berechtigungen geändert, ein anderer Prozess hat sie möglicherweise gelöscht oder geändert. Sie müssen also immer mit diesem Ausnahmefall umgehen, oder Sie haben wahrscheinlich einen Fehler.

5
Ben Barkay

Dies ist in vielen Frameworks üblich. Z.B. Hibernate macht genau das. Die Idee ist, dass die APIs für die Clientseite nicht aufdringlich sein sollten und Exception aufdringlich ist, da Sie explizit Code schreiben müssen, um sie an der Stelle zu verarbeiten, an der Sie die API aufrufen. Aber dieser Ort ist möglicherweise nicht der richtige Ort, um die Ausnahme überhaupt zu behandeln.
Um ehrlich zu sein, ist dies ein "heißes" Thema und viele Streitigkeiten, daher werde ich keine Seite vertreten, aber ich werde sagen, dass das, was Ihr Freund tut/vorschlägt, nicht ungewöhnlich oder ungewöhnlich ist.

2
user10326

Für eigenständige Anwendungen. Wenn Sie wissen, dass Ihre Anwendung die Ausnahme nicht behandeln kann, können Sie anstelle der aktivierten RuntimeException einen Fehler auslösen, die Anwendung abstürzen lassen, auf Fehlerberichte hoffen und Ihre Anwendung reparieren. (Siehe Antwort von mrmuggles für eine eingehendere Diskussion der Vor- und Nachteile von aktiviert und nicht aktiviert.)

2

In einer booleschen Frage ist es schwierig, nach zwei kontroversen Antworten anders zu antworten, aber ich möchte Ihnen eine Perspektive geben, die selbst an wenigen Stellen erwähnt wurde und für die Bedeutung, die sie hat, nicht genug betont wurde.

Mit den Jahren stellte ich fest, dass immer jemand über ein triviales Problem verwirrt ist und einige der Grundlagen nicht versteht.

Schichtung. Eine Softwareanwendung (sollte es zumindest sein) ist ein Stapel von Schichten übereinander. Eine wichtige Erwartung für eine gute Schichtung ist, dass die unteren Schichten Funktionen für potenziell mehrere Komponenten aus der oberen Schicht bereitstellen.

Angenommen, Ihre App verfügt über die folgenden Ebenen von unten nach oben: NET, TCP, HTTP, REST, DATENMODELL, BUSINESS.

Wenn Ihre Business-Schicht einen Rest-Anruf ausführen möchte, warten Sie eine Sekunde. Warum habe ich das gesagt? Warum habe ich keine HTTP-Anfrage oder TCP Transaktion oder Netzwerkpakete senden?) Gesagt, da diese für meine Geschäftsschicht irrelevant sind. Ich werde sie nicht behandeln, ich werde nicht in die Details schauen Ich bin vollkommen in Ordnung, wenn sie tief in den Ausnahmen stecken, die ich als Ursache bekomme, und ich möchte nicht wissen, dass sie überhaupt existieren.

Darüber hinaus ist es schlecht, wenn ich Details kenne, denn wenn ich morgen die unterstrichenen Transportprotokolle ändern möchte, die sich mit Details befassen, die für das TCP -Protokoll spezifisch sind, bedeutet dies, dass mein REST Abstraktion hat keine gute Arbeit geleistet, um sich von der spezifischen Implementierung zu abstrahieren.

Beim Übergang einer Ausnahme von Schicht zu Schicht ist es wichtig, jeden Aspekt zu überdenken und festzustellen, welchen Sinn dies für die Abstraktion hat, die die aktuelle Schicht bietet. Es kann sein, dass die Ausnahme durch eine andere ersetzt wird und mehrere Ausnahmen kombiniert werden. Es kann auch dazu führen, dass sie von aktiviert zu nicht aktiviert oder umgekehrt geändert werden.

Natürlich ist der Sinn der Orte, die Sie erwähnt haben, eine andere Geschichte, aber im Allgemeinen - ja, es könnte eine gute Sache sein, dies zu tun.

1
gsf

Die ganze Sache mit der "geprüften Ausnahme" ist eine schlechte Idee.

Die strukturierte Programmierung ermöglicht nur die Weitergabe von Informationen zwischen Funktionen (oder in Java Sprache, Methoden), wenn sie "in der Nähe" sind. Genauer gesagt können Informationen nur auf zwei Arten zwischen Funktionen verschoben werden:

  1. Vom Anrufer zum Angerufenen durch Argumentation.

  2. Vom Angerufenen zum Anrufer als Rückgabewerte.

Das ist eine grundsätzlich gute Sache. Dies ermöglicht es Ihnen, lokal über Ihren Code nachzudenken: Wenn Sie einen Teil Ihres Programms verstehen oder ändern müssen, müssen Sie nur diesen Teil und andere "in der Nähe" befindliche Teile betrachten.

Unter bestimmten Umständen ist es jedoch erforderlich, Informationen an eine "entfernte" Funktion zu senden, ohne dass jemand in der Mitte "weiß". Genau hier müssen Ausnahmen verwendet werden. Eine Ausnahme ist eine geheime Nachricht, die von einem Raiser (welcher Teil Ihres Codes auch immer eine throw Anweisung enthalten könnte) an einen Handler gesendet wird = (welcher Teil Ihres Codes auch immer einen catch Block enthalten mag, der mit der Ausnahme kompatibel ist, die thrown war).

Überprüfte Ausnahmen zerstören die Geheimhaltung des Mechanismus und damit den Grund für seine Existenz. Wenn es sich eine Funktion leisten kann, ihren Aufrufer eine Information "wissen" zu lassen, senden Sie diese Information einfach direkt als Teil des Rückgabewerts.

1
pyon

Dies kann von Fall zu Fall abhängen. In bestimmten Szenarien ist es ratsam, das zu tun, was Ihr Freund tut, z. B. wenn Sie eine API für einige Clients verfügbar machen und möchten, dass der Client die Implementierungsdetails am wenigsten kennt, wenn Sie wissen, dass bestimmte Implementierungsausnahmen spezifisch sein können Implementierungsdetails und für den Client nicht verfügbar.

Indem Sie die aktivierten Ausnahmen aus dem Weg räumen, können Sie APIs verfügbar machen, die es dem Client ermöglichen würden, saubereren Code zu schreiben, da der Client selbst möglicherweise die Ausnahmebedingungen vorab validiert.

Zum Beispiel nimmt Integer.parseInt (String) einen String und gibt das ganzzahlige Äquivalent zurück und löst eine NumberFormatException aus, falls der String nicht numerisch ist. Stellen Sie sich nun vor, eine Formularübermittlung mit einem Feld age wird durch diese Methode konvertiert, aber der Client hätte seinerseits bereits die Validierung sichergestellt, sodass es keinen Sinn macht, die Prüfung der Ausnahme zu erzwingen.

0
user94369

Hier gibt es wirklich ein paar Fragen

  1. Sollten Sie geprüfte Ausnahmen in ungeprüfte umwandeln?

Die allgemeine Faustregel lautet, dass Ausnahmen, die der Anrufer abfangen und wiederherstellen soll, überprüft werden sollten. Andere Ausnahmen (solche, bei denen das einzig vernünftige Ergebnis darin besteht, den gesamten Vorgang abzubrechen, oder bei denen Sie sie für unwahrscheinlich genug halten, dass es sich nicht lohnt, sich speziell um sie zu kümmern) sollten deaktiviert werden.

Manchmal unterscheidet sich Ihre Beurteilung, ob eine Ausnahme abgefangen und wiederhergestellt werden muss, von der der API, mit der Sie arbeiten. Manchmal ist der Kontext wichtig, eine Ausnahme, die es wert ist, in einer Situation behandelt zu werden, ist es möglicherweise nicht wert, in einer anderen behandelt zu werden. Manchmal wird Ihre Hand durch vorhandene Schnittstellen gezwungen. Ja, es gibt legitime Gründe, eine aktivierte Ausnahme in eine nicht aktivierte Ausnahme (oder in eine andere Art von aktivierter Ausnahme) umzuwandeln.

  1. Wenn Sie eine nicht aktivierte Ausnahme in eine aktivierte Ausnahme verwandeln möchten, wie sollten Sie dies tun?.

Stellen Sie zunächst und vor allem sicher, dass Sie die Ausnahmeverkettungsfunktion verwenden. Auf diese Weise gehen die Informationen aus der ursprünglichen Ausnahme nicht verloren und können zum Debuggen verwendet werden.

Zweitens müssen Sie entscheiden, welcher Ausnahmetyp verwendet werden soll. Die Verwendung einer einfachen Laufzeitausnahme erschwert es dem Anrufer, festzustellen, was schief gelaufen ist. Wenn der Anrufer jedoch versucht, festzustellen, was schief gelaufen ist, kann dies ein Hinweis darauf sein, dass Sie die Ausnahme nicht geändert haben sollten, um sie zu deaktivieren.

0
Peter Green