wake-up-neo.com

wirft die Exception endlich in Blöcken

Gibt es eine elegante Möglichkeit, Ausnahmen zu behandeln, die im finally-Block ausgegeben 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 vermeiden Sie die try/catch im finally-Block?

96
Paul

Ich mache es normalerweise so:

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

Anderswo:

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

Ich verwende normalerweise 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
    }
}
25
CJS

Wenn Sie Java 7 verwenden und resource implementiert AutoClosable, können Sie dies tun (am Beispiel von InputStream):

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

Ein bisschen übertrieben, aber vielleicht nützlich, wenn Sie Ausnahmen aufblähen lassen und nichts innerhalb Ihrer Methode protokollieren können (z. B. weil es sich um eine Bibliothek handelt und Sie den Aufrufcode lieber mit Ausnahmen und Protokollierung behandeln lassen):

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 habe mir dies etwas genauer angesehen und einen großartigen Blogpost von jemandem gefunden, der mehr darüber nachgedacht hat als ich: http://illegalargumentexception.blogspot.com/2008/10/Java-how-not-to -make-mess-of-stream.html Er geht noch einen Schritt weiter und kombiniert die beiden Ausnahmen in einer, die ich in manchen Fällen als nützlich erachten könnte.

8
MB.

Ab Java 7 müssen Sie nicht mehr explizit Ressourcen in einem finally - Block schließen, sondern können die try -with-resources-Syntax verwenden. Die try-with-resources-Anweisung ist eine try-Anweisung, die eine oder mehrere Ressourcen deklariert. Eine Ressource ist ein Objekt, das geschlossen werden muss, nachdem das Programm damit fertig ist. Die try-with-resources-Anweisung stellt sicher, dass jede Ressource am Ende der Anweisung geschlossen wird. Jedes Objekt, das Java.lang.AutoCloseable implementiert, das alle Objekte umfasst, die Java.io.Closeable implementieren, kann als Ressource verwendet werden.

Nehmen Sie den folgenden Code an:

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

Wenn eine Ausnahme auftritt, wird die close -Methode für jede dieser drei Ressourcen in umgekehrter Reihenfolge aufgerufen, in der sie erstellt wurden. Dies bedeutet, dass die close-Methode zuerst für ResultSetm, dann für die Anweisung und am Ende für das Connection-Objekt aufgerufen wird.

Es ist auch wichtig zu wissen, dass alle Ausnahmen, die beim automatischen Aufruf der close-Methode auftreten, unterdrückt werden. Diese unterdrückten Ausnahmen können von der in der Klasse Throwable definierten Methode getsuppressed () abgerufen werden.

Quelle: https://docs.Oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

6
Soroosh

Das Ignorieren von Ausnahmen, die in einem 'finally'-Block auftreten, ist im Allgemeinen a schlechte Idee Es sei denn, man weiß, was diese Ausnahmen sein werden und welche Bedingungen sie darstellen. Im normalen try/finally-Verwendungsmuster versetzt der try-Block die Dinge in einen Zustand, den der äußere Code nicht erwartet, und der finally-Block stellt den Zustand dieser Dinge auf den von dem äußeren Code erwarteten Zustand wieder her. Externer Code, der eine Ausnahme abfängt, erwartet im Allgemeinen, dass trotz der Ausnahme alles in einen normal-Zustand zurückversetzt wurde. Angenommen, ein Code startet eine Transaktion und versucht dann, zwei Datensätze hinzuzufügen. Der "finally" -Block führt eine "Zurücksetzung" durch, wenn keine Festschreibung erfolgt. Ein Aufrufer kann darauf vorbereitet sein, dass eine Ausnahme während der Ausführung der zweiten "Hinzufügen" -Operation auftritt, und er kann erwarten, dass sich die Datenbank in dem Zustand befindet, in dem sie sich befunden hat, bevor eine der beiden Operationen ausgeführt wurde. Wenn jedoch während des Rollbacks eine zweite Ausnahme auftritt, können Fehler auftreten, wenn der Aufrufer Annahmen über den Datenbankstatus trifft. Der Rollback-Fehler steht für a haupt Krise - eine, die nicht von Code erfasst werden sollte, der eine Ausnahme von "Fehler beim Hinzufügen des Datensatzes" erwartet.

Meine persönliche Neigung wäre es, eine Methode zum Abfangen einer Methode zu finden, die schließlich auftritt, und diese in eine "CleanupFailedException" umhüllen, wobei erkannt wird, dass ein solcher Fehler ein großes Problem darstellt und eine solche Ausnahme nicht leichtfertig erkannt werden sollte.

3
supercat

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

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

Aber manchmal kann man diesen zweiten Versuch nicht vermeiden. z.B. zum Schließen eines Streams

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 */ }
 }
2
Pierre

Nach vielem Nachdenken finde ich den folgenden Code am besten:

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 Folgendes:

  1. Die Ressource wird freigegeben, wenn der Code abgeschlossen ist
  2. Ausnahmen, die beim Schließen der Ressource ausgelöst werden, werden nicht verarbeitet, ohne dass sie verarbeitet werden.
  3. Der Code versucht nicht, die Ressource zweimal zu schließen. Es wird keine unnötige Ausnahme erstellt.
1
Grogi

Warum möchten Sie die zusätzliche Blockierung vermeiden? Da der finally-Block "normale" Operationen enthält, die eine Ausnahme auslösen können UND Sie möchten, dass der finally-Block vollständig ausgeführt wird, MÜSSEN Sie Ausnahmen abfangen.

Wenn Sie nicht erwarten, dass der finally-Block eine Exception auslöst und Sie sowieso nicht wissen, wie er mit der Exception umgehen soll (Sie würden nur die Stack-Trace-Anweisung erstellen), lassen Sie die Exception-Blase in den Aufruf-Stack aufsteigen (entfernen Sie den Try-Catch aus dem finally Block).

Wenn Sie die Eingabe reduzieren möchten, können Sie einen "globalen" äußeren Try-Catch-Block implementieren, der alle Ausnahmen fängt, die in final-Blöcken ausgelöst werden:

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

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

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}
1
Eduard Wirch

Resource von beste Antwort in Closeable ändern

Streams implementiert Closeable Damit können Sie die Methode für alle Streams wiederverwenden

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}
0
Ryan
try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Job erledigt. Keine Nulltests Einzelner Fang, einschließlich Ausnahmen für Erwerb und Freigabe. Natürlich können Sie das Execute Around-Idiom verwenden und müssen es nur einmal für jeden Ressourcentyp schreiben.

Ich mache das normalerweise:

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

Begründung: Wenn ich mit der Ressource fertig bin und das einzige Problem, das ich habe, das Schließen der Ressource ist, kann ich nicht viel dagegen tun. Es macht auch keinen Sinn, den ganzen Thread zu beenden, wenn ich mit der Ressource ohnehin fertig bin.

Dies ist einer der Fälle, in denen es zumindest für mich sicher ist, diese geprüfte Ausnahme zu ignorieren.

Bis heute hatte ich keine Probleme mit dieser Redewendung. 

0
OscarRyz

Wenn möglich, sollten Sie einen Test durchführen, um die Fehlerbedingung zunächst zu vermeiden.

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
  }
}

Außerdem sollten Sie wahrscheinlich nur Ausnahmen bemerken, von denen Sie sich erholen können. Wenn Sie dies nicht tun, können Sie es auf die oberste Ebene Ihres Programms übertragen. Wenn Sie nicht auf eine Fehlerbedingung testen können, müssen Sie Ihren Code mit einem Try-Catch-Block umgeben, wie Sie es bereits getan haben (obwohl ich empfehlen würde, bestimmte, erwartete Fehler abzufangen).

0
Ken Henderson

Sie könnten dies in eine andere Methode umwandeln ... 

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(); 
    }
  }
}
0
Sam Saffron