Ich habe darüber nachgedacht und konnte mir kein Beispiel einfallen lassen. Warum sollte jemand eine Ausnahme erwischen und nichts dagegen unternehmen wollen? Kannst du ein Beispiel geben? Vielleicht ist es nur etwas, was man niemals tun sollte.
Ich habe darüber nachgedacht und konnte mir kein Beispiel einfallen lassen. Warum sollte jemand eine Ausnahme erwischen und nichts dagegen unternehmen wollen? Kannst du ein Beispiel geben? Vielleicht ist es nur etwas, was man niemals tun sollte.
Antworten:
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.
}
Das heißt, ich denke, dass alle catch-Blöcke etwas enthalten sollten, auch wenn dies nur ein Kommentar ist, der erklärt, warum Sie die Ausnahme ignorieren.
Bearbeiten: Ich möchte auch betonen, dass Sie, wenn Sie so etwas tun, darauf achten sollten, nur die bestimmte Ausnahme zu erfassen, die Sie ignorieren möchten. Ein einfaches altes zu tun catch {}
ist fast immer eine schlechte Sache.
Ein Beispiel, bei dem ich denke, dass es in Ordnung ist, eine Ausnahme nur zu verschlucken, ohne etwas zu tun, selbst wenn die Ausnahme protokolliert wird, ist der Protokollierungscode selbst.
Wenn Sie versucht haben, etwas zu protokollieren und eine Ausnahme festgestellt haben, können Sie nicht viel dagegen tun:
So haben Sie die Möglichkeit, "das Geringste vom Bösen" im Hintergrund zu schlucken, sodass die Anwendung weiterhin ihre Hauptaufgabe erfüllen kann, ohne jedoch die Möglichkeit zur Fehlerbehebung zu beeinträchtigen.
Wenn eine Ausnahme von einer Operation ausgelöst wird, die ohnehin optional war, 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.
Fügen Sie in diesem Fall 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.
Leere catch
Blöcke riechen in den meisten Sprachen nach Code. Die Hauptidee ist, Ausnahmen für Ausnahmesituationen zu verwenden und sie nicht für die logische Steuerung zu verwenden. Alle Ausnahmen müssen irgendwo behandelt werden.
Infolge dieser Vorgehensweise haben Sie beim Programmieren einer bestimmten Anwendungsebene mehrere Möglichkeiten:
Das lässt eigentlich keinen Raum für nichts zu tun, leere catch
Blöcke.
EDITIERT ZUM HINZUFÜGEN : Angenommen, Sie programmieren in einer Sprache, in der das Auslösen von Ausnahmen die normale Methode zum Steuern der Programmlogik ist (eine der Alternativen zu goto
). Dann ist ein leerer catch
Block in einem Programm, das in dieser Sprache geschrieben ist, einem leeren else
Block in einer traditionellen Sprache (oder überhaupt keinem else
Block) sehr ähnlich . Ich glaube jedoch, dass dies nicht der von C # -, Java- oder C ++ - Entwicklergemeinschaften empfohlene Programmierstil ist.
In einigen Fällen müssen Sie in Java eine Ausnahme behandeln, die unter keinen Umständen jemals auftreten kann. Betrachten 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 auszulösen. Warum also damit umgehen? Sie können die try-catch-Klausel jedoch nicht einfach weglassen.
throw new Error(e)
, um absolut sicherzugehen, dass ich nichts verpasst habe (oder tatsächlich kaputte Plattform melde).
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 bei Mapping-Projekten, die nur einmal verwendet werden können und Abwechslung bieten).
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;
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 mit exitValue () überprüfen, ob der Prozess noch aktiv ist. Dabei wird eine IllegalThreadStateException ausgelöst, wenn der Prozess noch ausgeführt wird.
Nach meiner bescheidenen Erfahrung ist das selten gut. Ihr Kilometerstand kann jedoch variieren.
Fast jedes Mal, wenn ich dies in unserer Codebasis gesehen habe, ist dies darauf zurückzuführen, dass ich einen Fehler gefunden habe, den die verzehrte Ausnahme ausgeblendet hat. Anders ausgedrückt: Wenn Sie keinen Code bereitstellen, kann die Anwendung keinen Fehler anzeigen oder eine andere Aktion ausführen.
Manchmal möchten oder können Sie beispielsweise auf API-Ebenen möglicherweise keine Ausnahmen zurücklassen. In diesem Fall tendiere ich dazu, die allgemeinsten zu ermitteln und diese dann zu protokollieren. Nochmals, um zumindest einer Debug- / Diagnosesitzung eine Chance zu geben.
Wenn es leer sein muss , stelle ich in der Regel zumindest eine Behauptung auf, sodass zumindest während einer Debugsitzung etwas passiert. Das heißt, wenn ich nicht damit umgehen kann, neige ich dazu, sie komplett wegzulassen.
IMO gibt es eine Stelle, an der 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
}
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 weiterarbeiten soll, wenn eine bestimmte Operation fehlschlägt. Ich bin jedoch der Meinung, 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 dann nicht erfolgen, wenn das Programm in einem inkonsistenten Zustand bleibt oder wenn später ein anderer Teil des Codes ausfällt.
Ich glaube nicht, dass ich im Ausnahmefall keine Alarmstufe habe. Sollte eines der Ziele der Programmierung nicht darin bestehen, den Code zu verbessern? Wenn in 10% der Fälle eine Ausnahme auftritt und Sie nichts davon wissen, ist die Ausnahme immer so schlimm oder schlimmer.
Ich sehe jedoch die andere Seite: Wenn die Ausnahme bei der Codeverarbeitung keinen wirklichen Schaden anrichtet, warum sollte der Benutzer dann der Ausnahme ausgesetzt werden? Die Lösung, die ich normalerweise implementiere, besteht darin, sie von meiner Logger-Klasse protokollieren zu lassen (das ist in jeder einzelnen Klasse, die ich jemals bei der Arbeit schreibe).
Wenn es eine harmlose Ausnahme ist, rufe ich die .Debug () -Methode meines Loggers auf. ansonsten Logger.Error () (und (vielleicht) werfen).
try
{
doWork();
}
catch(BenignException x)
{
_log.Debug("Error doing work: " + x.Message);
}
Übrigens wird ein Aufruf der .Debug () -Methode in meiner Implementierung des Loggers nur protokolliert, wenn in meiner App.Config-Datei angegeben ist, dass sich die Programmausführungsprotokollebene im Debug-Modus befindet.
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.
Verweise
Das einzige Mal, dass ich so etwas wirklich tun musste, war eine Protokollierungsklasse für eine Konsolen-App. Es gab einen globalen Catch-Handler der obersten Ebene, der den Fehler an STDOUT sendete, den Fehler in einer Datei protokollierte und die App 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 wurde unabhängig davon exklusiv gesperrt. In diesem Fall konnte ich die Ausnahmebedingung nicht wie an anderer Stelle behandeln (abfangen, relevante Details protokollieren , einen besseren Ausnahmetyp einbinden usw.), da das Protokollieren der Ausnahmedetails dazu führte, dass der Logger dieselben Aktionen ausführte ( Versuch, in eine Datei zu schreiben), die bereits fehlgeschlagen war. 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 eine Ausnahme in einem Meldungsfeld angezeigt (nicht das, was Sie für eine stille 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 dies früher posten, ich hatte nur Angst, in Vergessenheit zu geraten. Da ich aber nicht der einzige bin ...)
Es ist in einer Situation in Ordnung, in der eine Sequenz ausgeführt werden muss, unabhängig davon, welches der kritischsten Teile am Ende steht.
Zum Beispiel. In Motion Control Kommunikation von Host zu Controller. In Notsituationen gibt es eine Reihe von Vorbereitungsschritten, um die Bewegung abzubrechen, die Trajektorienerzeugung zu stoppen, die Motoren abzubremsen, die Pausen zu aktivieren, den Verstärker zu deaktivieren und danach die Busspannung zu unterbrechen. Alle Schritte müssen nacheinander ausgeführt werden. Wenn einer der Schritte fehlschlägt, müssen die restlichen Schritte trotzdem ausgeführt werden, auch wenn das Risiko einer Beschädigung der Hardware in Kauf genommen wird. Sagen wir, auch wenn alles oben genannte fehlschlägt, muss der Kill-Bus-Strom trotzdem passieren.
Systemressourcen ordnungsgemäß schließen, um einen Fehler zu beheben
Zum Beispiel. Wenn Sie einen Dienst im Hintergrund ausführen, der dem Benutzer kein Feedback liefert, möchten Sie möglicherweise keine Fehlermeldung an den Benutzer senden , müssen jedoch die verwendeten Ressourcen ordnungsgemäß schließen.
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 Abfangmodus im Debug-Modus, um Fehler abzufangen und sie zum Testen an die Konsole oder in eine Protokolldatei zu drucken. In einer Produktionsumgebung wird allgemein erwartet, dass Hintergrunddienste den Benutzer nicht unterbrechen, wenn ein Fehler ausgegeben wird, sodass die Fehlerausgabe unterdrückt werden sollte.