Dies wird eher eine konzeptionelle Antwort darauf sein, warum diese Warnungen auch bei Ansätzen zum Ausprobieren von Ressourcen auftreten können. Es ist leider auch nicht die einfache Art von Lösung, die Sie sich erhoffen.
Fehlerbehebung kann nicht fehlschlagen
finally
modelliert einen Kontrollfluss nach einer Transaktion, der unabhängig davon ausgeführt wird, ob eine Transaktion erfolgreich ist oder fehlschlägt.
Im Fehlerfall wird finally
die Logik erfasst, die während der Wiederherstellung eines Fehlers ausgeführt wird, bevor dieser vollständig wiederhergestellt wurde (bevor wir unser catch
Ziel erreichen).
Stellen Sie sich das konzeptuelle Problem präsentiert es einen Fehler in der Begegnung Mitte von einem Fehler zurückzugewinnen.
Stellen Sie sich einen Datenbankserver vor, auf dem versucht wird, eine Transaktion festzuschreiben, die zur Hälfte fehlschlägt (der Server hat in der Mitte nicht genügend Arbeitsspeicher). Jetzt möchte der Server die Transaktion auf einen Punkt zurücksetzen, an dem nichts passiert ist. Stellen Sie sich jedoch vor, es stößt beim Zurücksetzen auf einen weiteren Fehler. Jetzt haben wir eine halb festgeschriebene Transaktion in der Datenbank - die Atomarität und die Unteilbarkeit der Transaktion sind jetzt aufgehoben, und die Integrität der Datenbank wird jetzt gefährdet.
Dieses konzeptionelle Problem tritt in jeder Sprache auf, die sich mit Fehlern befasst, unabhängig davon, ob es sich um C mit manueller Fehlercode-Weitergabe oder C ++ mit Ausnahmen und Destruktoren oder Java mit Ausnahmen und handelt finally
.
finally
kann nicht in Sprachen fehlschlagen, die es auf die gleiche Weise bereitstellen, wie Destruktoren in C ++ beim Auftreten von Ausnahmen nicht fehlschlagen können.
Die einzige Möglichkeit, dieses konzeptionelle und schwierige Problem zu vermeiden, besteht darin, sicherzustellen, dass beim Zurücksetzen von Transaktionen und Freigeben von Ressourcen in der Mitte möglicherweise keine rekursive Ausnahme / kein rekursiver Fehler auftritt.
Das einzig sichere Design ist also ein Design, bei dem writer.close()
es unmöglich ist, einen Fehler zu machen. Normalerweise gibt es im Entwurf Möglichkeiten, um Szenarien zu vermeiden, in denen solche Dinge mitten in der Wiederherstellung fehlschlagen können, was dies unmöglich macht.
Dies ist leider der einzige Weg - die Fehlerbehebung kann nicht fehlschlagen. Der einfachste Weg, dies sicherzustellen, besteht darin, diese Arten von "Ressourcenfreigabe" - und "Nebenwirkungen" -Funktionen nicht mehr funktionsfähig zu machen. Es ist nicht einfach - eine ordnungsgemäße Fehlerbehebung ist schwierig und leider auch schwer zu testen. Um dies zu erreichen, müssen Sie jedoch sicherstellen, dass bei Funktionen, die "zerstören", "schließen", "herunterfahren", "zurücksetzen" usw., möglicherweise keine externen Fehler auftreten, da solche Funktionen häufig auftreten müssen aufgerufen werden, während ein bestehender Fehler behoben wird.
Beispiel: Protokollierung
Angenommen, Sie möchten Daten in einem finally
Block protokollieren . Dies ist oft ein großes Problem, es sei denn, die Protokollierung kann nicht fehlschlagen . Die Protokollierung kann mit ziemlicher Sicherheit fehlschlagen, da möglicherweise mehr Daten an die Datei angehängt werden sollen, und dies kann leicht zu vielen Fehlern führen.
Die Lösung hier ist, es so zu machen, dass jede in finally
Blöcken verwendete Protokollierungsfunktion nicht zum Aufrufer geworfen werden kann (es könnte fehlschlagen, aber es wird nicht geworfen). Wie könnten wir das machen? Wenn Ihre Sprache das Werfen im Kontext von "Endlich" zulässt, vorausgesetzt, es gibt einen verschachtelten Try / Catch-Block, ist dies eine Möglichkeit, dem Aufrufer das Werfen zu vermeiden, indem Ausnahmen verschluckt und in Fehlercodes umgewandelt werden Prozess oder Thread, der separat und außerhalb eines vorhandenen Fehlerbehebungsstapels fehlschlagen kann, werden beendet. Solange Sie mit diesem Prozess kommunizieren können, ohne dass die Möglichkeit besteht, dass ein Fehler auftritt, ist dies auch ausnahmesicher, da das Sicherheitsproblem in diesem Szenario nur besteht, wenn wir rekursiv aus demselben Thread heraus werfen.
In diesem Fall können wir mit Protokollierungsfehlern davonkommen, vorausgesetzt, dass sie nicht ausgelöst werden, da das Fehlschlagen der Protokollierung und das Nichtstun nicht das Ende der Welt ist (es gehen keine Ressourcen verloren oder es werden keine Nebeneffekte zurückgesetzt, z. B.).
Wie auch immer, ich bin sicher, Sie können sich bereits vorstellen, wie unglaublich schwierig es ist, eine Software wirklich ausnahmesicher zu machen. Möglicherweise ist es nicht erforderlich, dies in vollem Umfang zu prüfen, es sei denn, es handelt sich um die unternehmenskritischste Software. Beachten Sie jedoch, wie Sie wirklich Ausnahmesicherheit erreichen können, da selbst sehr universelle Bibliotheksautoren häufig hier fummeln und die gesamte Ausnahmesicherheit Ihrer Anwendung durch die Verwendung der Bibliothek zunichte machen.
SomeFileWriter
Wenn Sie SomeFileWriter
die Option "inside" verwenden können close
, ist dies im Allgemeinen nicht mit der Ausnahmebehandlung kompatibel, es sei denn, Sie versuchen niemals, sie in einem Kontext zu schließen, in dem eine vorhandene Ausnahme behoben wird. Wenn der Code dafür außerhalb Ihrer Kontrolle liegt, handelt es sich möglicherweise um SOL. Es lohnt sich jedoch, die Autoren über dieses offensichtliche Problem mit der Ausnahmesicherheit zu informieren. Wenn es in Ihrer Kontrolle liegt, ist es meine Hauptempfehlung, sicherzustellen, dass das Schließen mit allen erforderlichen Mitteln nicht fehlschlagen kann.
Stellen Sie sich vor, ein Betriebssystem könnte eine Datei tatsächlich nicht schließen. Jetzt wird jedes Programm, das versucht, eine Datei beim Herunterfahren zu schließen, nicht mehr heruntergefahren . Was sollen wir jetzt tun? Halten Sie einfach die Anwendung offen und ignorieren Sie das Problem (möglicherweise in Ordnung, wenn es nicht so kritisch ist). Das sicherste Design: Machen Sie es so, dass es unmöglich ist, eine Datei nicht zu schließen.