Was ist eine unterdrückte Ausnahme?

76

In einem Kommentar (von user soc ) zu einer Antwort auf eine Frage zur Tail-Call-Optimierung wurde erwähnt, dass Java 7 aufgrund der "Hinzufügung von ARM" (Unterstützung für ARM-CPUs?) Eine neue Funktion namens "Unterdrückte Ausnahmen" hat.

Was ist in diesem Zusammenhang eine "unterdrückte Ausnahme"? In anderen Kontexten wäre eine "unterdrückte Ausnahme" eine Ausnahme, die abgefangen und dann ignoriert wurde (selten eine gute Idee). das ist eindeutig etwas anderes.

Raedwald
quelle
Ich sehe keine Erwähnung in der Beschreibung "Java Programming Language Enhancements" download.oracle.com/javase/7/docs/technotes/guides/language/…
Raedwald
18
ARM bedeutet automatisches Ressourcenmanagement, zB infoq.com/news/2010/08/arm-blocks
Daniel Kullmann
5
ARM ist in diesem Zusammenhang der alte Name für Try-with-Resources. Sie haben die Verwendung von ARM eingestellt und einige Zeit vor dem Versand von Java 7 begonnen, Try-with-Resources zu verwenden. Und @danielkullmann ist genau das, wofür ARM steht
Brad Cupit

Antworten:

55

Ich glaube, der Kommentator bezieht sich auf eine Ausnahme, die teilweise ignoriert wird, wenn sie im impliziten finallyBlock eines Try-with-Resources- Blocks im Kontext einer vorhandenen Ausnahme ausgelöst wird, die aus dem tryBlock ausgelöst wird :

Aus dem Codeblock, der der Anweisung try-with-resources zugeordnet ist, kann eine Ausnahme ausgelöst werden. Im Beispiel writeToFileZipFileContents kann eine Ausnahme aus dem try-Block ausgelöst werden, und bis zu zwei Ausnahmen können aus der try-with-resources-Anweisung ausgelöst werden, wenn versucht wird, die Objekte ZipFile und BufferedWriter zu schließen. Wenn eine Ausnahme aus dem try-Block ausgelöst wird und eine oder mehrere Ausnahmen aus der try-with-resources-Anweisung ausgelöst werden, werden die aus der try-with-resources-Anweisung ausgelösten Ausnahmen unterdrückt, und die vom Block ausgelöste Ausnahme ist diejenige Dies wird von der Methode writeToFileZipFileContents ausgelöst. Sie können diese unterdrückten Ausnahmen abrufen, indem Sie die Throwable.getSuppressed-Methode aus der vom try-Block ausgelösten Ausnahme aufrufen.

(Das zitiert einen Abschnitt namens "Unterdrückte Ausnahmen" von der verlinkten Seite.)

Jon Skeet
quelle
2
Relevanter API-Aufruf: download.oracle.com/javase/7/docs/api/java/lang/…
Raedwald
@ Raedwald: Meistens ja, ich denke schon.
Jon Skeet
6
@JonSkeet @Raedwald: Ich glaube, diese Antwort berücksichtigt nicht, dass unterdrückte Ausnahmen vor Java 7 existierten (ich spreche nicht von ignorierten Ausnahmen): Wenn ein finallyBlock eine Ausnahme auslöst, wenn der tryBlock auch eine Ausnahme auslöst, die ursprüngliche Ausnahme von der tryBlock ist verloren oder "unterdrückt" ( weitere Informationen finden Sie unter http://accu.org/index.php/journals/236 ). Java 7 hat gerade eine bequeme Methode zum Speichern der Ausnahme aus dem finallyBlock hinzugefügt , da diese finallyimplizit durch Try-with-Resources generiert wird.
JBert
5
Ein zu beachtender Punkt ist jedoch, dass, wenn wir in der try-with-resource-Anweisung explizit den endgültigen Block angeben und eine Ausnahme daraus ausgelöst wird, diese Vorrang vor den Ausnahmen hat, die aus dem try- oder try-with-resource-Block ausgelöst werden.
Aniket Thakur
63

Um das Zitat in Jons Antwort zu verdeutlichen, kann nur eine Ausnahme von einer Methode (pro Ausführung) try-with-resourcesausgelöst werden. Im Fall von a können jedoch mehrere Ausnahmen ausgelöst werden. Zum Beispiel könnte einer in den Block geworfen werden und ein anderer könnte aus dem impliziten geworfen werden, der von der finallybereitgestellt wird try-with-resources.

Der Compiler muss bestimmen, welche davon "wirklich" geworfen werden sollen. Es wird entschieden, die im expliziten Code (dem Code im tryBlock) ausgelöste Ausnahme anstelle der vom impliziten Code (dem finallyBlock) ausgelösten Ausnahme auszulösen . Daher werden die im impliziten Block ausgelösten Ausnahmen unterdrückt (ignoriert). Dies tritt nur bei mehreren Ausnahmen auf.

John B.
quelle
1
Unterdrückte Ausnahmen sind eine Folge der neuen Funktion, die bedeutet, dass wir beim Öffnen und Bearbeiten von Dateien keine umständlichen try... finallyKlauseln mehr schreiben müssen close(): stackoverflow.com/questions/3305405/…
Raedwald
@ JohnB Aber wir haben die Konstruktoroption Exception (anotherExcetion e) rit?
Kanagavelu Sugumar
3
@KanagaveluSugumar Der Exception(Exception cause)Konstruktor wird verwendet, um eine verursachende Ausnahme in eine andere zu verpacken, die möglicherweise aussagekräftiger ist. In diesem Fall handelt es sich jedoch um zwei unterschiedliche Ausnahmen, für die kein Kausalzusammenhang besteht. Ausnahme A hat keine Ausnahme B verursacht, daher wäre es nicht sinnvoll, eine in die andere zu wickeln. Außerdem nehmen Sie an, dass der Codierer die zweite Ausnahme explizit auslöst und Zugriff auf die erste hat. Dies wäre nicht der Fall, wenn beide durch Bibliotheksaufrufe ausgelöst würden.
John B
1
@ JohnB Ich denke deine Aussage ist falsch. "Der Compiler muss bestimmen, welche davon" wirklich "ausgelöst werden soll. Er entscheidet sich dafür, die im expliziten Code (dem Code im try-Block) ausgelöste Ausnahme auszulösen." Der Compiler wählt jedoch nur die endgültige Ausnahme und die try-Ausnahme wird unterdrückt.
Kanagavelu Sugumar
1
@ KanagaveluSugumar Pro Dokumentation:If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed
John B
21

Vor Java7; Es gibt Ausnahmen im Code, die aber irgendwie ignoriert wurden.

z.B)

public class SuppressedExceptions {
  public static void main(String[] args) throws Exception {
    try {
        callTryFinallyBlock();
    } catch (Exception e) {
        e.printStackTrace(); **//Only Finally Exception is Caught**
    }
  }

  private static void callTryFinallyBlock() throws Exception {
    try 
    {
        throw new TryException(); **//This is lost**
    }
    finally
    {
        FinallyException fEx = new FinallyException();
        throw fEx;
    }
  }
}

class TryException extends Exception {
}

class FinallyException extends Exception {
}

Ein neuer Konstruktor und zwei neue Methoden wurden der Throwable-Klasse in JDK 7 hinzugefügt. Diese sind wie folgt:

Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);

Mit diesem neuen Ansatz können wir auch diese unterdrückten Ausnahmen behandeln.

public class SuppressedExceptions {
  public static void main(String[] args) throws Exception {
    try {
        callTryFinallyBlock();
    } catch (Exception e) {
        e.printStackTrace();
        for(Throwable t: e.getSuppressed())
        {
            t.printStackTrace();
        }
    }
  }

  private static void callTryFinallyBlock() throws Exception {
    Throwable t = null;
    try 
    {
        throw new TryException();
    }
    catch (Exception e) {
        t = e;
    }
    finally
    {
        FinallyException fEx = new FinallyException();
        if(t != null)fEx.addSuppressed(t);
        throw fEx;
    }
  }
}

class TryException extends Exception {
}

class FinallyException extends Exception {
}

In Java7 versuchen Sie es mit Ressourcen. Die Ausnahme bei AutoCloseable :: close () wird standardmäßig zusammen mit der try-Ausnahme als unterdrückte Ausnahme hinzugefügt.

Beachten Sie auch, dass sich dies von verketteten Ausnahmen unterscheidet (wurden mit JDK 1.4 eingeführt und sollten es ermöglichen, Kausalzusammenhänge zwischen Ausnahmen leicht zu verfolgen).

Kanagavelu Sugumar
quelle
10

Den folgenden Code einräumen:

public class MultipleExceptionsExample {

   static class IOManip implements Closeable{
       @Override
       public void close() {
           throw new RuntimeException("from IOManip.close");
       }
   }

   public static void main(String[] args) {
       try(IOManip ioManip = new IOManip()){
           throw new RuntimeException("from try!");
       }catch(Exception e){
           throw new RuntimeException("from catch!");
       }finally{
           throw new RuntimeException("from finally!");
       }
   }
}

Mit allen Zeilen erhalten Sie: java.lang.RuntimeException: from finally!

Wenn finallySie den Block entfernen , erhalten Sie:java.lang.RuntimeException: from catch!

Wenn catchSie den Block entfernen , erhalten Sie:

Exception in thread "main" java.lang.RuntimeException: from try!
    Suppressed: java.lang.RuntimeException: from IOManip.close
Adil
quelle
9

Unterdrückte Ausnahmen sind zusätzliche Ausnahmen, die in einer Try-with-Resources-Anweisung ( eingeführt in Java 7 ) auftreten, wenn AutoCloseableRessourcen geschlossen werden. Da beim Schließen von AutoCloseableRessourcen mehrere Ausnahmen auftreten können, werden zusätzliche Ausnahmen als unterdrückte Ausnahmen an eine primäre Ausnahme angehängt .

Beim Betrachten des Bytecodes eines Beispielcodes für den Versuch mit Ressourcen werden Standard- JVM-Ausnahmebehandlungsroutinen verwendet, um die Semantik für den Versuch mit Ressourcen zu berücksichtigen.

Dan Cruz
quelle
0

Sie können Ausnahmen auch in Java 6 unterdrücken (ein kleiner Trick).

Ich habe ein Dienstprogramm erstellt, das das Unterdrücken von Ausnahmen in Java 1.6 und Java 1.7 transparent behandelt. Die Implementierung finden Sie hier

Sie müssen nur anrufen:

public static <T extends Throwable> T suppress(final T t, final Throwable suppressed) 

eine Ausnahme unterdrücken, und

public static Throwable [] getSuppressed(final Throwable t) {

um die unterdrückten Ausnahmen einer Ausnahme zu erhalten, falls noch jemand Java 1.6 verwendet

user2179737
quelle
0

ARM - Automatisches Ressourcenmanagement (eingeführt seit Java 7)

Nehmen Sie ein sehr einfaches Beispiel

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

Wenn nun die readLine()Funktion eine Ausnahme auslöst und dann sogar die close()Funktion [im Endblock] eine Ausnahme auslöst, erhält die letztere eine höhere Priorität und wird zurück zur aufrufenden Funktion geworfen. In diesem Fall ist dieException thrown by the readLine() method is ignored/suppressed . Sie können die verursachende Ausnahme in Ihrer Ausnahme verketten und Ihre Ausnahme aus dem endgültigen Blockieren erneut werfen.

Da java 7Funktionen zum Abrufen unterdrückter Ausnahmen bereitgestellt wurden. Sie können die public final java.lang.Throwable[] getSuppressed()Funktion für das abgefangene Wurfobjekt aufrufen, um die unterdrückten Ausnahmen anzuzeigen.

Zum Beispiel.

static String readFirstLineFromFileWithFinallyBlock(String path)
        throws Exception {
    try (BufferedReader br = new BufferedReader(new FileReader(path));) {
        return br.readLine();
    }
}

Wenn nun beim Schließen der Ressource eine br.readLine();Zeile ausgelöst Exception1und dann Exception2beispielsweise ausgelöst wird [Stellen Sie sich vor, dies geschieht in einem impliziten Endblock, den die Anweisung "try-with-resource" erstellt], unterdrückt Exception1 Exception2.

Einige Punkte, die hier zu beachten sind -

  1. Wenn der Try-with-Resource-Block eine Ausnahme auslöst, dh während der Ressourceninstanziierung, wird der Try-Block nicht ausgeführt und dieselbe Ausnahme wird ausgelöst.
  2. Wenn die Instanziierung der Ressource erfolgreich ist, löst der Try-Block eine Ausnahme aus, und beim Schließen der Ressource wird eine Ausnahme ausgelöst. Die beim Schließen der Ressource ausgelöste Ausnahme wird durch die vom Try-Block ausgelöste Ausnahme unterdrückt.
  3. Wenn Sie einen expliziten finally-Block angeben und eine Ausnahme von diesem Block ausgelöst wird, werden alle anderen Ausnahmen unterdrückt. (Dieser explizite finally-Block wird ausgeführt, nachdem Ressourcen geschlossen wurden.)

Ich habe die meisten möglichen Szenarien mit Codefragmenten kompiliert und im folgenden Beitrag ausgegeben.

Unterdrückte Ausnahmen in Java 7

Hoffentlich hilft das.

Aniket Thakur
quelle
1
In diesem Fall wird der Exceptionaus dem try {} -Block stammende Block jedoch nicht automatisch unterdrückt. Der Programmierer kann sich dafür entscheiden, was Sie nicht getan haben. Nur Versuche mit Ressourcen werden Ausnahmen bei Bedarf automatisch unterdrücken. Und wenn er es tut, wird die Ausnahme von Ihrem äquivalenten Endblock unterdrückt.
Martin Andersson
1
@ MartinAndersson Du hast recht. Hatte einige Verwirrung, als ich die Antwort geschrieben hatte. Ich hoffe, die bearbeitete Antwort lieferte bessere Einblicke.
Aniket Thakur
-1

Ich denke, das hat mit der "verketteten Ausnahmefunktion" zu tun. Dies wirkt sich darauf aus, wie eine Ausnahme von dieser Funktion behandelt wird, wenn sich die Stapelverfolgung weiterentwickelt. Im Laufe der Zeit können Ausnahmen, die Teil einer Gruppe verketteter Ausnahmen sind, unterdrückt werden. Weitere Informationen finden Sie in der Throwable-Dokumentation .

Jean-Simon LaRochelle
quelle