Frage

Ich hatte gerade eine ziemlich schmerzhaftes Problem Erfahrung einige Codes in der Fehlersuche, die wie folgt aussah:

try {
   doSomeStuff()
   doMore()
} finally {
   doSomeOtherStuff()
}

Das Problem war schwierig zu beheben, weil doSomeStuff () eine Ausnahme ausgelöst, die wiederum verursacht doSomeOtherStuff (), um auch eine Ausnahme zu werfen. Die zweite Ausnahme (durch den finally-Block geworfen) wurde zu meinem Code geworfen, aber es hat nicht einen Griff auf der ersten Ausnahme hat (geworfen von doSomeStuff ()), die die eigentlichen Wurzel-Ursache des Problems war.

Wenn der Code dies gesagt hatte, anstatt, wäre das Problem gewesen ohne weiteres ersichtlich:

try {
    doSomeStuff()
    doMore()
} catch (Exception e) {
    log.error(e);
} finally {
   doSomeOtherStuff()
}

Also, meine Frage ist:

Ist ein schließlich gebrauchte Block ohne catch-Block eine bekannte Java-anti-Muster? (Es scheint sicher eine nicht-leicht-scheinbare Unterklasse des offensichtlich bekannte anti-Musters zu sein „Keine Ausnahmen verschlingen!“)

War es hilfreich?

Lösung

In der Regel nein, das ist nicht ein Anti-Muster. Der Punkt, der schließlich Blöcke ist sicher Zeug wird gereinigt zu treffen, ob eine Ausnahme ausgelöst wird oder nicht. Der ganze Sinn der Ausnahmebehandlung ist, dass, wenn Sie nicht damit umgehen können, können Sie es sprudeln lassen jemanden, der kann durch die relativ sauber out-of-band-Signalisierung Exception Handling bietet. Wenn Sie sicher, dass Sachen wird gereinigt, wenn eine Ausnahme ausgelöst machen müssen, aber nicht richtig, die Ausnahme in dem aktuellen Bereich behandeln, dann ist dies genau das Richtige zu tun. Sie wollen einfach nur vielleicht ein wenig vorsichtiger darum, dass Ihr endlich Block wirft nicht sein.

Andere Tipps

Ich denke, die wirkliche „anti-Muster“ hier etwas in einem finally Block tut, die werfen, nicht nicht einen Haken hat.

nicht.

Was falsch ist, ist der Code innerhalb der schließlich.

Beachten Sie, dass schließlich immer noch ausgeführt werden und ist nur riskant (wie Sie gerade erlebt haben) etwas zu setzen, die es eine Ausnahme auslösen kann.

Es gibt absolut nichts falsch einen Versuch mit einem endlich und ohne Fang. Betrachten Sie das folgende:

InputStream in = null;
try {
    in = new FileInputStream("file.txt");
    // Do something that causes an IOException to be thrown
} finally {
    if (in != null) {
         try {
             in.close();
         } catch (IOException e) {
             // Nothing we can do.
         }
    }
}

Wenn eine Ausnahme ausgelöst wird und dieser Code nicht weiß, wie man damit umgeht dann die Ausnahme sollte den Call-Stack für den Anrufer sprudelt. In diesem Fall wollen wir noch den Strom bereinigen, so halte ich es durchaus Sinn macht, ohne einen Haken einen Try-Block zu haben.

Ich denke, es ist weit davon entfernt ein Anti-Muster zu sein und ist etwas, was ich sehr oft tun, wenn es kritisch ist zu tun ausplanen Ressourcen während der Ausführung der Methode erhalten.

Eine Sache, die ich tun, wenn sie mit Datei-Handles (zum Schreiben), die sich leert den Strom, bevor es mit dem IOUtils.closeQuietly Methode schließen, die keine Ausnahmen wirft:


OutputStream os = null;
OutputStreamWriter wos = null;
try { 
   os = new FileOutputStream(...);
   wos = new OutputStreamWriter(os);
   // Lots of code

   wos.flush();
   os.flush();
finally {
   IOUtils.closeQuietly(wos);
   IOUtils.closeQuietly(os);
}

ich es auf diese Weise aus den folgenden Gründen gerne tun:

  • Es ist nicht ganz sicher eine Ausnahme zu ignorieren, wenn eine Datei geschlossen wird - wenn es Bytes, die noch nicht in die Datei geschrieben wurden, dann wird die Datei in dem Zustand nicht der Anrufer erwarten würde sein kann;
  • Also, wenn eine Ausnahme während der Methode flush () angehoben wird, wird es an den Aufrufer propagiert werden, aber ich werde noch sicherstellen, dass alle Dateien geschlossen sind. Das Verfahren IOUtils.closeQuietly (...) ist weniger ausführlich dann die entsprechenden try ... catch ... ignorieren mich Block;
  • Wenn mehrere Ausgänge mit Strömen der Auftrag für die Methode flush () wichtig ist. Die Ströme, die durch Hindurchleiten andere Ströme als Konstruktoren erstellt wurden, sollten zunächst gespült werden. Das Gleiche gilt für die Methode close (), aber die flush () ist klar, meiner Meinung nach.

Ich würde sagen, ein Try-Block ohne catch-Block ist ein Anti-Muster. Sagen: „Ich eine nicht endlich hat ohne Fang“ ist eine Untergruppe von „Do einen Versuch nicht ohne einen Haken hat.“

Ich benutze try / finally in der folgenden Form:

try{
   Connection connection = ConnectionManager.openConnection();
   try{
       //work with the connection;
   }finally{
       if(connection != null){
          connection.close();           
       }
   }
}catch(ConnectionException connectionException){
   //handle connection exception;
}

Ich ziehe dies auf die try / catch / finally (+ verschachtelte try / catch in der endlich). Ich denke, dass es prägnanter ist und ich duplizieren nicht die catch (Exception).

try {
    doSomeStuff()
    doMore()
} catch (Exception e) {
    log.error(e);
} finally {
   doSomeOtherStuff()
}

Sie tun das auch nicht ... Sie nur mehr Fehler versteckt (auch nicht genau versteckte sie ... aber machte es schwieriger, mit ihnen fertig zu werden. Wenn Sie fangen Exception Sie auch jede Art von Runtime holen (wie Nullpointer und ArrayIndexOutOfBounds).

In der Regel fangen die Ausnahmen, die Sie fangen müssen (geprüfte Ausnahmen) und mit den anderen zu Testzeit beschäftigen. Runtime ist für Programmierer Fehler verwendet werden. - und Programmierfehler sind Dinge, die nicht in einem ordnungsgemäß gedebuggt Programm passieren sollten

Meiner Meinung nach ist es mehr der Fall, die mit einem finally catch irgendeine Art von Problem hinweisen. Die Ressource Idiom ist sehr einfach:

acquire
try {
    use
} finally {
    release
}

In Java können Sie eine Ausnahme von so ziemlich überall haben. Oft ist die acquire eine geprüfte Ausnahme auslöst, die vernünftige Art und Weise zu handhaben ist, einen Haken um den, wie viel zu setzen. Sie nicht, einige scheußliche null Kontrolle versuchen.

Wenn Sie wirklich anal sein würden, sollten Sie beachten, dass es implizierte Prioritäten unter Ausnahmen. Zum Beispiel sollten alle Thread clobber, ob es von acquire / Nutzung / Veröffentlichung kommt. diese Prioritäten richtig Handhabung ist unansehnlich.

Daher abstrakt Ihre Ressource Umgang weg mit der Execute Around Idiom.

Versuche / ist schließlich ein Weg, um richtig freie Ressourcen. Der Code im finally-Block sollte niemals werfen, da sie nur auf Ressourcen oder Staat handeln sollte, die vor dem Eintritt in den try-Block übernommen wurde.

Als beiseite, ich denke, log4j ist fast ein Anti-Muster.

Wenn Sie ein RUNNING Programm verwendet ordnungsgemäße Untersuchung TOOL ZUR KONTROLLE (das heißt ein Debugger, IDE oder in einem extremen Sinne eines Weber-Byte-Code, aber NICHT LOGGING AUSSAGEN IN all paar LINES SETZEN!).

In den beiden Beispielen präsentieren Ihnen die erste richtig aussieht. Die zweite beinhaltet die Logger-Code und führt einen Fehler. Im zweiten Beispiel eine Ausnahme zu unterdrücken, wenn man durch die ersten beiden Aussagen ausgelöst wird (dh Sie es zu fangen und sie lügen, aber nicht erneut auslösen. Das ist etwas, was ich sehr häufig in log4j Verwendung finde und ist ein echtes Problem des Anwendungsdesigns. Im Grunde genommen mit der Änderung machen Sie das Programm nicht in eine Art und Weise, das sehr hart für das System, das Sie im Grunde weiter zu handhaben wäre seit März, als ob Sie nie eine Ausnahme (sorta wie VB Grund auf Fehler Lebenslauf nächstes Konstrukt).

hatten

try-finally kann Ihnen helfen, copy-paste-Code, falls ein Verfahren hat mehrere return Aussagen zu reduzieren. Betrachten Sie das folgende Beispiel (Android Java):

boolean doSomethingIfTableNotEmpty(SQLiteDatabase db) {
    Cursor cursor = db.rawQuery("SELECT * FROM table", null);
    if (cursor != null) { 
        try {
            if (cursor.getCount() == 0) { 
                return false;
            }
        } finally {
            // this will get executed even if return was executed above
            cursor.close();
        }
    }
    // database had rows, so do something...
    return true;
}

Wenn es keine finally Klausel war, könnte man cursor.close() zweimal schreiben. Kurz vor return false und auch nach der umgebenden if Klausel

Ich denke, dass versuchen, ohne Haken ist, anti-Muster. Mit try / catch behandeln außergewöhnlichen Bedingungen (Datei IO Fehler, Socket-Timeout, etc.) ist kein anti-Muster.

Wenn Sie versuchen, verwenden / schließlich für die Bereinigung, sollten Sie einen mit Block statt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top