Ich schreibe eine App, die eine Verbindung zu einer Website herstellt und eine Zeile daraus liest. Ich mache es so:
%Vor%Ist es gut? Ich meine, ich schließe den BufferedReader in der letzten Zeile, aber ich schließe den InputStreamReader nicht. Soll ich einen eigenständigen InputStreamReader aus dem connection.getInputStream und einen BufferedReader aus dem eigenständigen InputStreamReader erstellen, um alle zwei Reader zu schließen? Ich denke, es wird besser sein, die abschließenden Methoden wie folgt in den finally Block zu stellen:
%Vor%Aber es ist hässlich, weil die Closing-Methoden eine Exception auslösen können, also muss ich sie behandeln oder werfen.
Welche Lösung ist besser? Oder was wäre die beste Lösung?
Das allgemeine Idiom für Ressourcenerwerb und -freigabe in Java ist:
%Vor%Hinweis:
try
sollte dem Erwerb sofort folgen. Dies bedeutet, dass Sie es nicht in den Decorator einwickeln und die Sicherheit beibehalten können (und das Entfernen von Leerzeichen oder das Einfügen von Dingen in eine Zeile hilft nicht:). finally
, andernfalls ist sie nicht ausnahmslos sicher. null
, verwenden Sie final
. Andernfalls haben Sie unordentlichen Code und Potenzial für NPEs. try
-Block abgefangen werden (Java führt Sie hier in die Irre). Sie können diesen Unsinn mit dem Execute Around idiom abstrahieren, also Sie Wiederhole dich nicht (schreibe einfach eine Menge Text).
Es reicht, den BufferedReader zu schließen - dies schließt auch den zugrunde liegenden Reader.
Yishai hat ein schönes Muster gepostet , um die Streams zu schließen (Schließen könnte eine weitere Ausnahme auslösen).
Ist es gut? Ich meine, ich schließe den BufferedReader in der letzten Zeile, aber ich schließe den InputStreamReader nicht.
Abgesehen davon, dass es in der finally
gemacht werden sollte (damit die Schließung auch im Falle einer Ausnahme gewährleistet ist), ist es in Ordnung. Die Java-IO-Klassen verwenden das Decorator-Muster. Der Abschluss wird an die zugrunde liegenden Streams delegiert.
Aber es ist hässlich, weil die Closing-Methoden eine Exception auslösen können, also muss ich sie handhaben oder werfen.
Wenn das Schließen eine Ausnahme auslöst, bedeutet dies oft, dass die andere Seite geschlossen oder gelöscht wurde, was völlig außerhalb Ihrer Kontrolle liegt. Sie können es höchstens protokollieren oder ignorieren. In einer einfachen Anwendung würde ich es einfach ignorieren. In einer missionskritischen Anwendung würde ich es loggen, nur um sicher zu sein.
In einer Nut kann Ihr Code wie folgt umgeschrieben werden:
%Vor%In Java 7 gibt es eine automatische Ressourcenbehandlung, die Ihren Code so übersichtlich wie:
gemacht hat %Vor%Siehe auch:
Sie deklarieren eine Variable, ohne sie zuzuweisen ( null
zählt nicht - in diesem Fall ist es eine nutzlose Zuweisung). Dies ist ein Code "Geruch" in Java (ref Wirksames Java ; Code abgeschlossen für mehr auf Variablendeklaration).
Zuerst müssen Sie nur den obersten Stream-Decorator schließen ( br
schließt isr
). Zweitens, wenn br.close()
eine Ausnahme auslöst, würde isr.close()
nicht aufgerufen, also ist dies kein Soundcode. Unter bestimmten Ausnahmebedingungen verdeckt Ihr Code die ursprüngliche Ausnahme mit NullPointerException
.
Wenn das (zugegebenermaßen unwahrscheinliche) Ereignis, dass der InputStreamReader
-Konstruktor irgendeine Art von Laufzeitausnahme ausgelöst hat, würde der Stream von der Verbindung nicht geschlossen werden.
Nutzen Sie die Schnittstelle Closeable
, um die Redundanz zu reduzieren.
So würde ich Ihren Code schreiben:
%Vor%Beachten Sie Folgendes:
Vor einiger Zeit habe ich einige Zeit darüber nachgedacht, wie ich Vermeiden Sie das Lecken von Ressourcen / Daten, wenn etwas schief geht .
Ich denke, es wird besser sein, die Schließmethoden im finally-Block
Ja, immer. Da eine Ausnahme auftreten kann und Ressourcen nicht ordnungsgemäß freigegeben / geschlossen werden.
Sie müssen nur den äußersten Leser schließen, da er dafür verantwortlich ist, alle umgebenden Leser zu schließen.
Ja, es ist hässlich ... vorerst. Ich denke, es gibt Pläne für eine automatische Ressourcenverwaltung in Java.
Ich würde Apache Commons IO dafür verwenden, wie andere vorgeschlagen haben, hauptsächlich IOUtils.toString (InputStream) und IOUtils.closeQuietly(InputStream) :
%Vor%Sie brauchen für java.io keine verschachtelten Anweisungen für verschachtelte Streams und Reader. Es ist sehr selten, dass Sie mehr als eine Sache in einer einzigen schließen müssen - die meisten Konstruktoren können eine Ausnahme auslösen, also würden Sie versuchen, Dinge zu schließen, die Sie noch nicht erstellt haben.
Wenn Sie den Stream schließen möchten, ob der Lesevorgang erfolgreich ist oder nicht, müssen Sie ihn in ein finally einfügen.
Weisen Sie Variablen nicht null zu und vergleichen Sie sie dann, um zu sehen, ob etwas früher passiert ist; Strukturieren Sie Ihr Programm stattdessen so, dass der Pfad, in dem Sie den Stream schließen, nur erreicht werden kann, wenn die Ausnahme nicht ausgelöst wird. Abgesehen von den Variablen, mit denen in For-Schleifen iteriert wird, sollten Variablen ihren Wert nicht ändern müssen - ich neige dazu, alles Endgültige zu markieren, es sei denn, es besteht die Notwendigkeit, etwas anderes zu tun. Wenn Sie Flags in Ihrem Programm haben, um Ihnen zu sagen, wie Sie zu dem gerade ausgeführten Code gekommen sind, und dann das Verhalten basierend auf diesen Flags zu ändern, ist das ein sehr prozeduraler (nicht einmal strukturierter) Programmierstil.
Wie Sie die try / catch / finally-Blöcke verschachteln, hängt davon ab, ob Sie die Ausnahmen, die von den verschiedenen Stufen ausgelöst werden, anders behandeln möchten.
%Vor% getEncoding
muss die Ergebnisse der getContentEncoding()
und getContentType()
der Verbindung prüfen, um die Kodierung der Webseite zu bestimmen; Ihr Code verwendet nur die Standardkodierung der Plattform, die möglicherweise falsch ist.
Ihr Beispiel ist jedoch in strukturierten Begriffen ungewöhnlich, da es sehr prozedural ist; normalerweise würden Sie das Drucken und das Abrufen in einem größeren System trennen und dem Clientcode erlauben, jede Ausnahme zu behandeln (oder manchmal eine benutzerdefinierte Ausnahme abzufangen und zu erstellen):
%Vor% Wie McDowell sagte, müssen Sie möglicherweise den Eingabestream schließen, wenn new InputStreamReader
wirft.
Tags und Links java exception-handling url inputstream