it-swarm-eu.dev

Ist es jemals in Ordnung, eine leere catch-Anweisung zu haben?

Ich dachte darüber nach und konnte kein Beispiel finden. Warum sollte jemand eine Ausnahme fangen und nichts dagegen unternehmen wollen? Kannst du ein Beispiel geben? Vielleicht ist es nur etwas, was niemals getan werden sollte.

61
ysolik

Ich mache es die ganze Zeit mit Dingen wie Konvertierungsfehlern in D:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

Trotzdem denke ich, dass alle Catch-Blöcke etwas enthalten sollten, auch wenn dieses Etwas nur ein Kommentar ist, der warum erklärt. Sie ignorieren die Ausnahme.

Bearbeiten: Ich möchte auch betonen, dass Sie, wenn Sie so etwas tun, darauf achten sollten, nur die spezifische Ausnahme zu erfassen, die Sie ignorieren möchten. Ein einfaches altes machen catch {} ist fast immer eine schlechte Sache.

78
dsimcha

Ein Beispiel, bei dem ich denke, dass es in Ordnung ist, eine Ausnahme einfach zu schlucken, ohne etwas zu tun, selbst wenn die Ausnahme protokolliert wird, befindet sich im Protokollierungscode selbst.

Wenn Sie versucht haben, etwas zu protokollieren und eine Ausnahme erhalten haben, können Sie nicht viel dagegen tun:

  • sie können es natürlich nicht protokollieren;
  • möglicherweise können Sie auf einen Reserveprotokollierungsmechanismus zurückgreifen, aber die meisten Anwendungen sind nicht so ausgefeilt, und für diejenigen, die ausgereift genug sind, tritt das gleiche Entwurfsproblem mit dem Reserveprotokollierungsmechanismus auf.
  • fast Fail - ist für die meisten Anwendungen eine zu radikale Lösung.
  • das Auslösen einer Ausnahme bringt wenig, da sie in einer catch-Anweisung auf dem Stapel endet, die mit ziemlicher Sicherheit versucht, sie zu protokollieren ...

Dadurch haben Sie die Möglichkeit, das Problem "am wenigsten zu lösen", es leise zu schlucken, sodass die Anwendung ihre Hauptaufgabe weiterhin ausführen kann, aber die Fähigkeit zur Fehlerbehebung beeinträchtigt.

50
kdubinets

Wenn eine Ausnahme durch eine ohnehin optionale Operation ausgelöst wird, ist möglicherweise nichts zu tun. Es ist möglicherweise nicht sinnvoll, es zu protokollieren. In diesem Fall möchten Sie es vielleicht nur fangen und nichts tun.

Wenn Sie dies tun, fügen Sie einen Kommentar hinzu. Kommentieren Sie immer alles, was wie ein Fehler aussieht (Durchfall in einer switch -Anweisung, leerer catch -Block, Zuweisung in einer Bedingung).

Sie könnten argumentieren, dass dies keine ordnungsgemäße Verwendung von Ausnahmen ist, aber das ist eine andere Frage.

8
David Thornley

In einigen Fällen müssen Sie Java] eine Ausnahme behandeln, die unter absolut keinen Umständen jemals auftreten kann. Beachten Sie diesen Code:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

Jede Implementierung der Java -Plattform) ist erforderlich, um die folgenden Standardzeichensätze zu unterstützen.

...

UTF-8

Ohne Ihre Java Plattform) zu beschädigen, gibt es einfach keine Möglichkeit, diese Ausnahme jemals zu verursachen. Warum also die Mühe machen, damit umzugehen? Aber Sie können die try-catch-Klausel nicht einfach weglassen.

6
user281377

In der Regel nein. Sie möchten entweder die Ausnahme auf den Stapel werfen oder protokollieren, was passiert ist.

Ich mache dies jedoch oft, wenn ich Zeichenfolgen analysiere und in Zahlen konvertiere (insbesondere beim Zuordnen von Projekten, die einmal verwendet werden und weggeworfen werden).

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;
6
Fil

Leere catch Blöcke sind in den meisten Sprachen ein Codegeruch. Die Hauptidee besteht darin, Ausnahmen für Ausnahmesituationen zu verwenden und sie nicht zur logischen Steuerung zu verwenden. Alle Ausnahmen müssen irgendwo behandelt werden.

Als Konsequenz dieses Ansatzes haben Sie beim Programmieren einer bestimmten Anwendungsschicht mehrere Möglichkeiten:

  • nichts gegen die Ausnahme tun. Es wird von einer anderen Schicht gefangen und gehandhabt
  • fangen Sie es und führen Sie die Korrekturmaßnahme durch.
  • fangen Sie es, tun Sie etwas, aber werfen Sie es erneut, damit eine andere Schicht damit umgehen kann

Dies lässt nicht wirklich Raum für nichts zu tun, leere catch Blöcke.

EDITED TO ADD: Angenommen, Sie programmieren in einer Sprache, in der das Auslösen von Ausnahmen die normale Methode zur Steuerung der Programmlogik ist (eine der Alternativen zu goto). Dann ähnelt ein leerer catch-Block in einem in dieser Sprache geschriebenen Programm einem leeren else-Block in einer traditionellen Sprache (oder überhaupt keinem else-Block). Ich glaube jedoch, dass dies nicht der von C #, Java oder C++ - Entwicklungsgemeinschaften empfohlene Programmierstil ist.

6
azheglov

In einigen Fällen ist die Ausnahme überhaupt nicht außergewöhnlich. in der Tat wird es erwartet. Betrachten Sie dieses Beispiel:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

Da es in Java.lang.Process () keine isAlive () -Methode gibt, können Sie nur überprüfen, ob sie noch aktiv ist, indem Sie exitValue () aufrufen, das eine IllegalThreadStateException auslöst, wenn der Prozess noch ausgeführt wird.

3
user281377

Nach meiner bescheidenen Erfahrung ist das selten gut. Ihr Kilometerstand kann jedoch variieren.

Fast jedes Mal, wenn ich dies in unserer Codebasis gesehen habe, habe ich einen Fehler aufgespürt, den die verzehrte Ausnahme verborgen hat. Anders ausgedrückt: Ohne Code kann die Anwendung keinen Fehler anzeigen oder eine andere Aktion ausführen.

Manchmal, zum Beispiel auf API-Ebenen, möchten oder können Sie Ausnahmen möglicherweise nicht zulassen. In diesem Fall versuche ich, die allgemeinsten zu erfassen und diese dann zu protokollieren. Noch einmal, um zumindest einer Debug-/Diagnosesitzung eine Chance zu geben.

Wenn es muss leer sein muss, setze ich normalerweise mindestens eine Behauptung auf, sodass zumindest während einer Debug-Sitzung etwas passiert. Das heißt, wenn ich damit nicht umgehen kann, neige ich dazu, sie komplett wegzulassen.

2
DevSolo

IMO gibt es einen Ort, an dem leere catch-Anweisungen in Ordnung sind. In Testfällen, in denen Sie eine Ausnahme erwarten:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}
2

Ich glaube, es gibt bestimmte Fälle, in denen es gerechtfertigt ist, eine leere catch-Klausel zu haben. Dies sind Fälle, in denen der Code einfach weiterlaufen soll, wenn eine bestimmte Operation fehlschlägt. Ich denke jedoch, dass dieses Muster leicht überbeansprucht werden kann, daher sollte jede Verwendung genau untersucht werden, um sicherzustellen, dass es keinen besseren Weg gibt, damit umzugehen. Dies sollte insbesondere niemals erfolgen, wenn das Programm in einem inkonsistenten Zustand belassen wird oder wenn später ein anderer Teil des Codes fehlschlagen könnte.

2
o. nate

Die Existenzprüfung ist ein guter Anwendungsfall:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

Ein anderer Fall ist, wenn eine finally -Klausel verwendet wird:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

Es gibt einen Vorschlag, das Weglassen der Fangbindung in ECMAScript zuzulassen, der sich auf diesen und ähnliche Anwendungsfälle bezieht.

Referenzen

1
Paul Sweatte

Ich glaube nicht daran, dass bei einer Ausnahme keine Alarmstufe vorhanden ist. Sollte eines der Ziele der Programmierung nicht darin bestehen, den Code zu verbessern? Wenn eine Ausnahme in 10% der Fälle auftritt und Sie nie davon erfahren, ist die Ausnahme immer so schlimm oder schlimmer.

Ich sehe jedoch auf der anderen Seite, dass wenn die Ausnahme bei der Verarbeitung von Code keinen wirklichen Schaden anrichtet, warum der Benutzer dann dieser ausgesetzt wird. Die Lösung, die ich normalerweise implementiere, besteht darin, sie von meiner Logger-Klasse protokollieren zu lassen (dh in jeder einzelnen Klasse, die ich jemals bei der Arbeit schreibe).

Wenn es sich um eine harmlose Ausnahme handelt, rufe ich die .Debug () -Methode meines Loggers auf. Andernfalls wird Logger.Error () (und (vielleicht) werfen).

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

Übrigens: Wenn ich in meiner Implementierung meines Loggers die .Debug () -Methode aufrufe, wird sie nur protokolliert, wenn in meiner App.Config-Datei angegeben ist, dass sich die Programmausführungsprotokollstufe im Debug-Modus befindet.

1
Tim Claason

Es ist in einer Situation in Ordnung, in der eine Sequenz ausgeführt werden muss, egal was mit dem kritischsten Stück am Ende platziert wird.

Zum Beispiel. In Motion Control Kommunikation des Hosts zum Controller. In Notsituationen gibt es eine Reihe von Vorbereitungsschritten, um die Bewegung abzubrechen, die Trajektorienerzeugung zu stoppen, Motoren abzubremsen, Unterbrechungen zu aktivieren, den Verstärker zu deaktivieren. Danach müssen Sie die Busleistung abschalten. Alles muss nacheinander geschehen, und wenn einer der Schritte fehlschlägt, müssen die restlichen Schritte trotzdem ausgeführt werden, auch wenn das Risiko einer Beschädigung der Hardware akzeptiert wird. Sagen Sie, selbst wenn alles oben Genannte fehlschlägt, muss die Kill-Bus-Stromversorgung trotzdem erfolgen.

0
user7071

Das einzige Mal, dass ich so etwas wirklich tun musste, war mit einer Protokollierungsklasse für eine Konsolen-App. Es gab einen globalen Catch-Handler der obersten Ebene, der den Fehler an STDOUT ausgab, den Fehler in einer Datei protokollierte und die App dann mit einem Fehlercode> 0 schloss.

Das Problem hierbei war, dass manchmal die Protokollierung in der Datei fehlschlug. Die Verzeichnisberechtigungen haben Sie daran gehindert, die Datei zu schreiben. Die Datei war unabhängig davon ausschließlich gesperrt. In diesem Fall konnte ich die Ausnahme nicht auf die gleiche Weise behandeln wie an anderer Stelle (catch, Protokollieren der relevanten Details, Einschließen eines besseren Ausnahmetyps usw.), da das Protokollieren der Ausnahmedetails den Protokollierer verursachte die gleichen Aktionen ausführen (versuchen, in eine Datei zu schreiben), die bereits fehlgeschlagen waren. Als sie wieder versagten ... Sie sehen, wohin ich gehe. Es gerät in eine Endlosschleife.

Wenn Sie einige der try {} -Blöcke löschen, wird möglicherweise die Ausnahme in einem Meldungsfeld angezeigt (nicht das, was Sie für eine unbeaufsichtigte Konfigurations-App wünschen). Bei dieser Methode, die in die Protokolldatei schreibt, habe ich einen leeren Catch-Handler. Dies begräbt den Fehler nicht, da Sie immer noch den Fehlercode> 0 erhalten. Es stoppt lediglich die Endlosschleife und ermöglicht es der App, ordnungsgemäß zu beenden.

Es gibt natürlich einen Kommentar, der erklärt, warum es leer ist.

(Ich wollte das früher posten, ich hatte nur Angst, in Vergessenheit zu geraten. Da ich aber nicht der einzige bin ...)

0
JohnL

Systemressourcen ordnungsgemäß schließen, um einen Fehler zu beheben

Zum Beispiel. Wenn Sie einen Dienst im Hintergrund ausführen, der dem Benutzer kein Feedback gibt, möchten Sie dem Benutzer möglicherweise keine Fehleranzeige senden, aber Sie müssen do Schließen die Ressourcen werden auf anmutige Weise verwendet.

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

Idealerweise verwenden Sie den Catch im Debug-Modus, um Fehler abzufangen und zum Testen an die Konsole oder in eine Protokolldatei zu drucken. In einer Produktionsumgebung wird im Allgemeinen erwartet, dass Hintergrunddienste den Benutzer nicht unterbrechen, wenn ein Fehler ausgelöst wird, sodass die Fehlerausgabe unterdrückt werden sollte.

0
Evan Plaice