Frage

Gibt es eine elegante Möglichkeit, Ausnahmen zu behandeln, die in finally Block geworfen werden?

Zum Beispiel:

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

Wie beurteilen Sie die try / catch im finally Block vermeiden?

War es hilfreich?

Lösung

Ich mache es in der Regel wie folgt aus:

try {
  // Use the resource.
} catch( Exception ex ) {
  // Problem with the resource.
} finally {
  // Put away the resource.
  closeQuietly( resource );
}

In anderen Ländern:

protected void closeQuietly( Resource resource ) {
  try {
    if (resource != null) {
      resource.close();
    }
  } catch( Exception ex ) {
    log( "Exception during Resource.close()", ex );
  }
}

Andere Tipps

ich verwende in der Regel eine der closeQuietly Methoden in org.apache.commons.io.IOUtils:

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}

Wenn Sie mit Java 7 und resource implementiert AutoClosable, Sie können dies tun (mit Input als Beispiel):

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}

Die wohl ein bisschen übertrieben, aber vielleicht nützlich, wenn Sie Ausnahmen sprudeln sind zu lassen und man kann nichts log aus Ihrer Methode (zB weil es sich um eine Bibliothek ist, und Sie würden lieber die Berufung Code Handle Ausnahmen lassen und Logging):

Resource resource = null;
boolean isSuccess = false;
try {
    resource = Resource.create();
    resource.use();
    // Following line will only run if nothing above threw an exception.
    isSuccess = true;
} finally {
    if (resource != null) {
        if (isSuccess) {
            // let close throw the exception so it isn't swallowed.
            resource.close();
        } else {
            try {
                resource.close();
            } catch (ResourceException ignore) {
                // Just swallow this one because you don't want it 
                // to replace the one that came first (thrown above).
            }
        }
    }
}

UPDATE: Ich in diesen sah ein wenig mehr und fand eine große Blog-Post von jemandem, der deutlich über das mehr als ich gedacht hat: http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of -stream.html Er geht einen Schritt weiter und kombiniert die beiden Ausnahmen in eine, die ich in einigen Fällen nützlich sein sehen konnte.

Wie von Java 7 Sie müssen nicht mehr explizit schließen Ressourcen in einem schließlich Block stattdessen können Sie verwenden versuchen -mit-Ressourcen Syntax. Die Try-mit-Ressourcen-Anweisung ist eine try-Anweisung, die eine oder mehr Ressourcen erklärt. Eine Ressource ist ein Objekt, das geschlossen werden muss, nachdem das Programm damit beendet ist. Die Try-mit-Ressourcen-Anweisung stellt sicher, dass jede Ressource am Ende der Anweisung geschlossen wird. Jedes Objekt, das java.lang.AutoCloseable implementiert, die alle Objekte enthält, die java.io.Closeable implementieren, können als Ressource verwendet werden.

Nehmen wir den folgenden Code:

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

Wenn eine Ausnahme ist nun mal die schließen Methode wird auf jedem dieser drei Ressourcen in umgekehrter Reihenfolge aufgerufen werden, in dem sie erstellt wurden. Es bedeutet die engen Verfahren würden zunächst für ResultSetm dann der Erklärung und am Ende für das Connection-Objekt aufgerufen werden.

Es ist auch wichtig zu wissen, dass alle Ausnahmen, die die Nähe Methoden auftreten, wenn automatisch unterdrückt aufgerufen wird. Diese unterdrückt Ausnahmen können in der Throwable Klasse definiert durch getsuppressed () Methode abgerufen werden.

Quelle: https://docs.oracle.com/javase/ tutorial / essential / Ausnahmen / tryResourceClose.html

Ausnahmen zu ignorieren, die in einem ‚schließlich‘ Block auftreten ist in der Regel ein schlechte Idee , wenn man nicht weiß, was diese Ausnahmen werden und welche Bedingungen sie repräsentieren. Im normalen try/finally Nutzungsmuster legt der try Block Dinge in einen Zustand des Außen Code wird diese Dinge nicht Zustand, was der Außen Code erwartet, und der finally Block wieder erwarten. Außerhalb Code, der eine Ausnahme abfängt wird in der Regel erwarten, dass trotz der Ausnahme, alles wurde zu einem normal Zustand gestellt. Angenommen, einige Code, um eine Transaktion startet und dann versucht, zwei Datensätze hinzuzufügen; der „endlich“ Block führt einen „Rollback, wenn nicht begangen“ -Betrieb. Ein Anrufer könnte eine Ausnahme hergestellt werden, die während der Ausführung des zweiten „add“ Operation auftreten und kann erwarten, dass, wenn es eine solche Ausnahme abfängt, wird die Datenbank in dem Zustand sein, es war, bevor entweder Operation versucht wurde. Wenn jedoch eine zweite Ausnahme während des Rollbacks auftritt, könnten schlechte Dinge passieren, wenn die Anrufer keine Annahmen über den Datenbank-Status machen. Der Rollback-Ausfall stellt eine große Krise -. Eine, die durch Code gefangen werden soll, nicht nur ein „Failed Datensatz hinzufügen“ erwartet Ausnahme

Meine persönliche Neigung wäre eine schließlich Methode fangen Ausnahmen zu haben, die sie in einer „CleanupFailedException“ auftreten und wickelt, zu erkennen, dass dieses Versäumnis ein großes Problem darstellt und ein solche Ausnahme sollte nicht leicht gefangen werden.

Eine Lösung, wenn die beiden Ausnahmen sind zwei verschiedene Klassen

try {
    ...
    }
catch(package1.Exception err)
   {
    ...
   }
catch(package2.Exception err)
   {
   ...
   }
finally
  {
  }

Aber manchmal kann man nicht diesen zweiten Try-Catch vermeiden. z.B. zum Schließen eines Stromes

InputStream in=null;
try
 {
 in= new FileInputStream("File.txt");
 (..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
 }
catch(SQLException err)
 {
 //handle exception
 }
finally
 {
 //at the end, we close the file
 if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
 }

Warum wollen Sie den zusätzlichen Block vermeiden wollen? Da der finally-Block „normale“ Operationen enthält, die eine Ausnahme auslösen können und wollen Sie das schließlich vollständig zu laufen blockieren HABEN Sie Ausnahmen zu fangen.

Wenn Sie nicht erwarten, die schließlich blockieren, eine Ausnahme zu werfen, und Sie wissen nicht, wie die Ausnahme behandeln sowieso (Sie würden nur Stack-Trace-Dump) lassen die Ausnahme Blase den Call-Stack nach oben (entfernen Sie die try-catch aus dem finally-Block).

Wenn Sie die Eingabe reduzieren Sie einen „globalen“ äußerte try-catch-Block implementieren könnten, die alle Ausnahmen in finally-Blöcken geworfen werden fangen:

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}

Nach vielen Überlegung finde ich den folgenden Code am besten kann:

MyResource resource = null;
try {
    resource = new MyResource();
    resource.doSomethingFancy();
    resource.close(); 
    resource = null;  
} finally {
    closeQuietly(resource)
}

void closeQuietly(MyResource a) {
    if (a!=null)
        try {
             a.close();
        } catch (Exception e) {
             //ignore
        }
}

Dieser Code garantiert folgende:

  1. Die Ressource freigegeben wird, wenn der Code fertig
  2. geworfen Ausnahmen, wenn die Ressource zu schließen, ohne die Verarbeitung sie nicht verbraucht werden.
  3. Der Code versucht nicht, die Ressource zweimal, keine unnötige Ausnahme schließen erstellt werden.

Wenn Sie sollen Sie testen, um den Fehlerzustand zu vermeiden, mit zu beginnen.

try{...}
catch(NullArgumentException nae){...}
finally
{
  //or if resource had some useful function that tells you its open use that
  if (resource != null) 
  {
      resource.Close();
      resource = null;//just to be explicit about it was closed
  }
}

Auch sollten Sie wahrscheinlich nur sein fangen Ausnahmen, die Sie von sich erholen kann, wenn man dann nicht wiederherstellen können lassen Sie es auf die oberste Ebene des Programms verbreiten. Wenn Sie nicht für einen Fehlerzustand testen, dass Sie Ihren Code mit einem Try-Catch-Block umgeben müssen, wie Sie bereits getan haben (obwohl ich empfehlen würde immer noch fangen spezifischen, erwarteten Fehler).

Sie können diese in einer anderen Methode Refactoring ...

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}

ich in der Regel tun dies:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

Begründung: Wenn ich mit der Ressource und das einzige Problem fertig bin ich es schließt, gibt es nicht viel ich dagegen tun kann. Es ist auch nicht sinnvoll, den ganzen Thread zu töten, wenn ich sowieso mit der Ressource fertig bin.

Dies ist einer der Fälle, in denen zumindest für mich, es ist sicher zu ignorieren, die Ausnahme überprüft.

Bis heute habe ich kein Problem mit diesem Idiom habe.

try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Job getan. Keine Null-Tests. Einzel Fang, umfassen erwerben und Ausnahmen veröffentlichen. Natürlich können Sie die Execute Around Idiom verwenden und nur für jeden Ressourcentyp einmal schreiben.

Ändern Resource von beste Antwort Closeable

Streams implementiert Closeable So können Sie die Methode für alle Ströme wieder verwenden

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top