web-dev-qa-db-fra.com

Java non interceptée?

J'ai un petit problème théorique avec les constructions try-catch.

J'ai passé un examen pratique hier à propos de Java et je ne comprends pas l'exemple suivant:

try {
    try {
        System.out.print("A");
        throw new Exception("1");
    } catch (Exception e) {
        System.out.print("B");
        throw new Exception("2");
    } finally {
        System.out.print("C");
        throw new Exception("3");
    }
} catch (Exception e) {
    System.out.print(e.getMessage());
}

La question était "à quoi ressemblera la sortie?"

J'étais à peu près sûr que ce serait AB2C3, MAIS surprise, ce n'est pas vrai.

La bonne réponse est ABC3 (testé et c'est vraiment comme ça).

Ma question est la suivante: où est passée l’exception ("2")?

169
Kousalik

À partir de spécification de langage Java 14.20.2. :

Si le bloc catch se termine brusquement pour la raison R, le bloc finally est exécuté. Ensuite, il y a un choix:

  • Si le bloc finally se termine normalement, l'instruction try se termine brutalement pour la raison R.

  • Si le bloc finally s'achève abruptement pour la raison S, l'instruction try s'achève abruptement pour la raison S (et la raison R est ignorée) .

Donc, quand il y a un bloc catch qui lève une exception:

try {
    // ...
} catch (Exception e) {
    throw new Exception("2");
}

mais il y a aussi un dernier bloc qui lève une exception:

} finally {
    throw new Exception("3");
}

Exception("2") sera ignoré et seul Exception("3") sera propagé.

196
Adam Siemion

Les exceptions lancées dans block finalement suppriment l'exception lancée plus tôt dans le bloc try ou catch.

Exemple Java 7: http://ideone.com/0YdeZo

De l'exemple Javadoc :


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

Toutefois, dans cet exemple, si les méthodes readLine et les deux exceptions sont levées, la méthode readFirstLineFromFileWithFinallyBlock lève l'exception renvoyée par le bloc finally; l'exception levée depuis le bloc try est supprimée.


Le nouveau try-with syntaxe de Java 7 ajoute une autre étape de suppression des exceptions: les exceptions générées dans le bloc try suppriment celles renvoyées précédemment dans la partie try-with.

du même exemple:

try (
        Java.util.Zip.ZipFile zf = new Java.util.Zip.ZipFile(zipFileName);
        Java.io.BufferedWriter writer = Java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    ) {
        for (Java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {
            String newLine = System.getProperty("line.separator");
            String zipEntryName = ((Java.util.Zip.ZipEntry)entries.nextElement()).getName() + newLine;
            writer.write(zipEntryName, 0, zipEntryName.length());
        }
    }

Une exception peut être levée à partir du bloc de code associé à l'instruction try-with-resources. Dans l'exemple ci-dessus, une exception peut être levée à partir du bloc try et deux exceptions au maximum peuvent être levées à partir de l'instruction try-with-resources lorsqu'elle tente de fermer les objets ZipFile et BufferedWriter. Si une exception est générée à partir du bloc try et qu'une ou plusieurs exceptions sont levées à partir de l'instruction try-with-resources, ces exceptions sont supprimées à partir de l'instruction try-with-resources et sont supprimées. qui est levé par la méthode writeToFileZipFileContents. Vous pouvez récupérer ces exceptions supprimées en appelant la méthode Throwable.getSuppressed à partir de l'exception levée par le bloc try.


Dans le code de la question, chaque bloc supprime clairement l'ancienne exception, sans même la consigner, ce qui n'est pas bon lorsque vous essayez de résoudre certains bogues:

http://en.wikipedia.org/wiki/Error_hiding

19
S.D.

Puisque throw new Exception("2"); est lancé à partir de catch block et non de try, il ne sera plus attrapé.
Voir 14.20.2. Exécution de try-finally et try-catch-finally.

C'est ce qui se passe:

try {
    try {
        System.out.print("A");         //Prints A
        throw new Exception("1");   
    } catch (Exception e) { 
        System.out.print("B");         //Caught from inner try, prints B
        throw new Exception("2");   
    } finally {
        System.out.print("C");         //Prints C (finally is always executed)
        throw new Exception("3");  
    }
} catch (Exception e) {
    System.out.print(e.getMessage());  //Prints 3 since see (very detailed) link
}
9
Maroun

Votre question est très évidente, et la réponse est simple dans la même mesure. L'objet Exception avec le message "2" est écrasé par l'objet Exception avec le message "3".

Explication: Quand une exception se produit, son objet est lancé pour attraper un bloc à manipuler. Mais lorsqu'une exception survient dans le bloc catch même, son objet est transféré au bloc OUTER CATCH (le cas échéant) pour la gestion des exceptions. Et pareil est arrivé ici. L'objet d'exception avec le message "2" est transféré au bloc OUTER catch. Mais attendez .. Avant de quitter le bloc try-catch intérieur, il DOIT EXÉCUTER ENFIN. Voici le changement qui nous préoccupe. Un nouvel objet EXCEPTION (avec le message "3") est jeté ou ce dernier bloc qui a remplacé l'objet Exception déjà levé (avec le message "2"). En conséquence, lorsque le message de l'objet Exception est imprimé, nous avons valeur surchargée c'est-à-dire "3" et non "2".

Keep Remember: un seul objet exception peut être traité par bloc CATCH.

5
Bharat

Le bloc finally est toujours exécuté. Soit vous return de l'intérieur du bloc try, soit une exception est levée. L'exception levée dans le bloc finally remplacera celle levée dans la branche catch.

De plus, le lancement d'une exception ne provoquera aucune sortie par lui-même. La ligne throw new Exception("2"); n'écrira rien.

2
allprog

Selon votre code:

try {
    try {
        System.out.print("A");
        throw new Exception("1");   // 1
    } catch (Exception e) {
        System.out.print("B");      // 2
        throw new Exception("2");
    } finally {                     // 3
        System.out.print("C");      // 4 
        throw new Exception("3");
    }
} catch (Exception e) {             // 5
    System.out.print(e.getMessage());
}

Comme vous pouvez le voir ici:

  1. affiche A et lève une exception # 1;
  2. cette exception a été interceptée par une instruction catch et print B - # 2;
  3. bloquer enfin # 3 s'exécute après l'instruction try-catch (ou uniquement try, si aucune exception n'est survenue) et affiche C - # 4 et jeté une nouvelle exception;
  4. celui-ci a été attrapé par une déclaration de capture externe # 5;

Le résultat est ABC3. Et 2 est omis de la même manière que 1

0
nazar_art