Frage

Eines der Dinge, die nervt mich immer über Leser und Streams in Java ist, dass die close() Methode eine Ausnahme auslösen kann. Da es eine gute Idee, in einem finally-Block die enge Methode zu setzen, erfordert, dass ein bisschen eine schwierige Situation. Normalerweise verwende ich diese Konstruktion:

FileReader fr = new FileReader("SomeFile.txt");
try {
    try {
        fr.read();
    } finally {
        fr.close();
    }
} catch(Exception e) {
    // Do exception handling
}

Aber ich habe auch diese Konstruktion gesehen:

FileReader fr = new FileReader("SomeFile.txt");
try {
    fr.read() 
} catch (Exception e) {
    // Do exception handling
} finally {
    try {
        fr.close();
    } catch (Exception e) {
        // Do exception handling
    }
}

Ich ziehe den ersten Bau, weil es nur ein catch-Block ist und es scheint, nur eleganter. Gibt es einen Grund, um tatsächlich die zweite oder eine alternative Konstruktion zu bevorzugen?

UPDATE: Würde es einen Unterschied machen, wenn ich, dass beide read und close nur IOExceptions werfen hingewiesen? So scheint es wahrscheinlich zu mir, dass, wenn lesen kann, in der Nähe wird aus dem gleichen Grunde versagen.

War es hilfreich?

Lösung

Ich würde immer für das erste Beispiel gehen.

Wenn die Nähe eine Ausnahme werfen ist (in der Praxis, die für einen Filereader nie passieren wird), würde nicht der normale Weg, dass der Umgangs mit einer Ausnahme angemessen an den Anrufer zu werfen? Die enge Ausnahme trumpft mit ziemlicher Sicherheit ein Problem Sie die Ressource hatte verwenden. Die zweite Methode ist wahrscheinlich besser geeignet, wenn Ihre Vorstellung von Ausnahmebehandlung ist System.err.println zu nennen.

Es ist eine Frage, wie weit Ausnahmen geworfen werden sollte. Thread sollte immer erneut ausgelöst werden, aber eine Ausnahme innerhalb würde endlich damit aufhören. Ebenso sollten Fehler werfen weiter als Runtime und Runtime weiter als geprüfte Ausnahmen. Wenn Sie wirklich Sie wollen Code schreiben könnte, diesen Regeln zu folgen, und dann abstrakt es mit dem „execute um“ Idiom.

Andere Tipps

Ich fürchte, ein großes Problem mit dem ersten Beispiel gibt es, das ist, dass, wenn eine Ausnahme geschieht am oder nach dem Lesen, der finally Block ausgeführt. So weit, ist es gut. Aber was, wenn die fr.close() bewirkt dann eine weitere Ausnahme geworfen werden? Dies wird „Trumpf“ die erste Ausnahme (ein bisschen wie return in einem finally Block setzen) und finden Sie alle Informationen verlieren, was tatsächlich verursacht das Problem zu beginnen.

Ihr schließlich Block sollte verwendet werden:

IOUtil.closeSilently(fr);

, wo diese Hilfsmethode gerade tut:

public static void closeSilently(Closeable c) {
    try { c.close(); } catch (Exception e) {} 
} 

Ich ziehe die zweite. Warum? Wenn beide read() und close() Ausnahmen werfen, einer von ihnen verloren gehen könnte. Bei der ersten Konstruktion, überschreibt die Ausnahme von close() die Ausnahme von read(), während in dem zweiten, die Ausnahme von close() separat gehandhabt wird.


Wie von Java 7, rel="nofollow die Try-mit- Ressourcen konstruieren diese viel einfacher macht , ohne sich um Ausnahmen zu kümmern zu lesen.

try (FileReader fr = new FileReader("SomeFile.txt")) {
    fr.read();
    // no need to close since the try-with-resources statement closes it automatically
}

Mit Ausnahmebehandlung:

try (FileReader fr = new FileReader("SomeFile.txt")) {
    fr.read();
    // no need to close since the try-with-resources statement closes it automatically
} catch (IOException e) {
    // Do exception handling
    log(e);
    // If this catch block is run, the FileReader has already been closed.
    // The exception could have come from either read() or close();
    // if both threw exceptions (or if multiple resources were used and had to be closed)
    // then only one exception is thrown and the others are suppressed
    // but can still be retrieved:
    Throwable[] suppressed = e.getSuppressed(); // can be an empty array
    for (Throwable t : suppressed) {
        log(suppressed[t]);
    }
}

Nur ein Try-Catch benötigt wird und alle Ausnahmen sicher gehandhabt werden können. Sie können immer noch einen finally Block, wenn Sie möchten, aber es gibt keine Notwendigkeit, die Ressourcen zu schließen.

Wenn beide lesen und schließen eine Ausnahme, die Ausnahme von lesen wird 1. So in Option ausgeblendet werden, die zweite Option tut mehr Fehlerbehandlung.

Doch in den meisten Fällen wird die erste Option noch bevorzugt werden.

  1. In vielen Fällen können Sie nicht mit Ausnahmen in der Methode beschäftigen sie erzeugt werden, aber Sie müssen noch den Strom innerhalb dieser Operation Handhabung kapseln.
  2. Versuchen Sie, einen Autor zu dem Code hinzufügen und sehen Sie, wie ausführlich der zweite Ansatz wird.

Wenn Sie alle erzeugten Ausnahmen übergeben müssen, kann es erfolgen.

Der Unterschied, soweit ich sehen kann, ist, dass es verschiedene Ausnahmen und Ursachen im Spiel auf verschiedenen Ebenen und die

catch (Exception e)

verschleiert, dass. Der einzige Punkt, der mehrere Ebenen ist Ihre Ausnahmen zu unterscheiden, und was Sie dagegen tun können:

try
{
  try{
   ...
  }
   catch(IOException e)
  {
  ..
  }
}
catch(Exception e)
{
  // we could read, but now something else is broken 
  ...
}

Normalerweise mache ich die folgenden. Zunächst definieren Sie eine Vorlage-Methode basiert Klasse mit dem Try / Catch-Chaos umgehen

import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public abstract class AutoFileCloser {
    private static final Closeable NEW_FILE = new Closeable() {
        public void close() throws IOException {
            // do nothing
        }
    };

    // the core action code that the implementer wants to run
    protected abstract void doWork() throws Throwable;

    // track a list of closeable thingies to close when finished
    private List<Closeable> closeables_ = new LinkedList<Closeable>();

    // mark a new file
    protected void newFile() {
        closeables_.add(0, NEW_FILE);
    }

    // give the implementer a way to track things to close
    // assumes this is called in order for nested closeables,
    // inner-most to outer-most
    protected void watch(Closeable closeable) {
        closeables_.add(0, closeable);
    }

    public AutoFileCloser() {
        // a variable to track a "meaningful" exception, in case
        // a close() throws an exception
        Throwable pending = null;

        try {
            doWork(); // do the real work

        } catch (Throwable throwable) {
            pending = throwable;

        } finally {
            // close the watched streams
            boolean skip = false;
            for (Closeable closeable : closeables_) {
                if (closeable == NEW_FILE) {
                    skip = false;
                } else  if (!skip && closeable != null) {
                    try {
                        closeable.close();
                        // don't try to re-close nested closeables
                        skip = true;
                    } catch (Throwable throwable) {
                        if (pending == null) {
                            pending = throwable;
                        }
                    }
                }
            }

            // if we had a pending exception, rethrow it
            // this is necessary b/c the close can throw an
            // exception, which would remove the pending
            // status of any exception thrown in the try block
            if (pending != null) {
                if (pending instanceof RuntimeException) {
                    throw (RuntimeException) pending;
                } else {
                    throw new RuntimeException(pending);
                }
            }
        }
    }
}

Beachten Sie die „pending“ Ausnahme -. Diese kümmert sich um den Fall, in dem eine Ausnahme während der Nähe geworfen würde eine Ausnahme maskieren könnten wir wirklich wichtig

Die schließlich versucht, von außen jeder dekoriert Strom zu schließen zuerst, wenn Sie also eine BufferedWriter hatte einen Filewriter Einwickeln, versuchen wir, die BuffereredWriter zuerst zu schließen, und wenn das nicht funktioniert, immer noch versuchen, die Filewriter selbst zu schließen.

Sie können die oben Klasse wie folgt verwenden:

try {
    // ...

    new AutoFileCloser() {
        @Override protected void doWork() throws Throwable {
            // declare variables for the readers and "watch" them
            FileReader fileReader = null;
            BufferedReader bufferedReader = null;
            watch(fileReader = new FileReader("somefile"));
            watch(bufferedReader = new BufferedReader(fileReader));

            // ... do something with bufferedReader

            // if you need more than one reader or writer
            newFile(); // puts a flag in the 
            FileWriter fileWriter = null;
            BufferedWriter bufferedWriter = null;
            watch(fileWriter = new FileWriter("someOtherFile"));
            watch(bufferedWriter = new BufferedWriter(fileWriter));

            // ... do something with bufferedWriter
        }
    };

    // .. other logic, maybe more AutoFileClosers

} catch (RuntimeException e) {
    // report or log the exception
}

Mit diesem Ansatz, den Sie nie über die try / catch / finally wieder Dateien mit Schließung zu tun kümmern.

Wenn dies für Ihren Einsatz zu schwer ist, denkt zumindest etwa nach dem try / catch und der „pending“ Variable Ansatz verwendet es.

Die Standardkonvention I verwenden, dass Sie keine Ausnahmen entkommen muss lassen blockieren ein schließlich.

Das ist, weil, wenn eine Ausnahme bereits die Ausnahme aus der schließlich Willen Trumpf geworfen Vermehrung die ursprüngliche Ausnahme blockieren (und somit verloren).

In 99% der Fälle dies nicht der Fall ist, was wollen Sie wie die ursprüngliche Ausnahme ist wahrscheinlich die Ursache des Problems (alle sekundären Ausnahmen Nebenwirkungen von der ersten sein, sondern verschleiern Ihre Fähigkeit, die Quelle der ursprünglichen Ausnahme zu finden und also das eigentliche Problem).

So Ihr grundlegender Code sollte wie folgt aussehen:

try
{
    // Code
}
// Exception handling
finally
{
    // Exception handling that is garanteed not to throw.
    try
    {
         // Exception handling that may throw.
    }
    // Optional Exception handling that should not throw
    finally()
    {}
}

Ich mag den Ansatz von @ Chris Marshall, aber Ich mag nie Ausnahmen sehen still geschluckt zu werden. Ich denke, die beste Ausnahmen zu protokollieren, vor allem, wenn Sie unabhängig sind contiuing.

ich immer eine Utility-Klasse verwende diese Art von gemeinsamen Ausnahmen zu behandeln, aber ich würde diese winzigen anders seine Antwort machen.

Ich würde immer einen Logger verwenden (log4j für mich) Fehler zu protokollieren etc.

IOUtil.close(fr);

Eine leichte Modifikation des Hilfsmethode:

public static void close(Closeable c) {
    try {
      c.close();
    } catch (Exception e) {
      logger.error("An error occurred while closing. Continuing regardless", e); 
    } 
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top