169 votes

Une exception Java n'a pas été détectée ?

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

J'ai passé un examen pratique hier sur 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 de savoir "à quoi ressemblera le résultat".

J'étais presque sûr que ce serait AB2C3, MAIS suprise suprise, ce n'est pas vrai.

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

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

196voto

Adam Siemion Points 6314

De la Spécification du langage Java 14.20.2. :

Si le bloc catch se termine brusquement pour la raison R, alors le bloc finally est exécuté. Il y a alors un choix à faire :

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

  • Si le bloc finally se termine brusquement pour la raison S, alors l'instruction try se termine brusquement pour la raison S (et la raison R est écartée). .

Donc, quand il y a un bloc catch qui lance une exception :

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

mais il y a aussi un bloc final qui lève également une exception :

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

Exception("2") seront rejetées et seules les Exception("3") sera propagé.

19voto

S.D. Points 12816

Les exceptions lancées dans le bloc finally suppriment les exceptions lancées précédemment dans le bloc try ou catch.

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

De La Javadoc exemple :


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

Cependant, dans cet exemple, si les méthodes readLine et close lèvent toutes deux des exceptions des exceptions, alors la méthode readFirstLineFromFileWithFinallyBlock lève l'exception levée par le bloc finally ; l'exception levée par le bloc try est supprimée. l'exception générée par le bloc try est supprimée.


Le nouveau try-with de Java 7 ajoute une nouvelle étape dans la suppression des exceptions : Les exceptions lancées dans le bloc d'essai suppriment celles lancé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 lancée depuis le bloc try, et jusqu'à deux exceptions peuvent être lancées à partir de l'instruction try-with-resources lorsqu'elle tente de fermer le fichier ZipFile et BufferedWriter. Si une exception est levée dans le bloc et qu'une ou plusieurs exceptions sont levées par l'instruction try-with-resources, alors les exceptions lancées par l'instruction l'instruction try-with-resources sont supprimées, et l'exception levée par l'instruction par le bloc est celle qui est levée par l'instruction writeToFileZipFileContents. Vous pouvez récupérer ces exceptions supprimées exceptions supprimées en appelant la méthode Throwable.getSuppressed à partir de la exception lancée par le bloc try.


Dans le code de la question, chaque bloc rejette purement et simplement l'ancienne exception, sans même l'enregistrer, ce qui n'est pas bon lorsque l'on essaie de résoudre des bogues :

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

9voto

Maroun Maroun Points 31217

Depuis throw new Exception("2"); est lancé à partir de catch et non try il ne sera pas attrapé de nouveau.
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
}

5voto

Sarkar Points 325

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

Explication : Lorsqu'une exception se produit, son objet est lancé dans le bloc catch pour être traité. Mais lorsque l'exception se produit dans le bloc catch lui-même, son objet est transféré au bloc CATCH OUTER (s'il existe) pour le traitement de l'exception. Et la même chose s'est produite ici. L'objet d'exception avec le message "2" est transféré au bloc d'interception externe. Mais attendez. .. Avant de quitter le bloc try-catch interne, il DOIT S'EXÉCUTER FINALEMENT. C'est ici que se produit le changement qui nous préoccupe. Un nouvel objet EXCEPTION (avec le message "3") est lancé hors de ce bloc finally qui a remplacé l'objet Exception déjà lancé (avec le message "2"). En conséquence, lorsque le message de l'objet Exception est imprimé, nous avons obtenu une valeur écrasée, c'est-à-dire "3" et non "2".

N'oubliez pas : un seul objet d'exception peut être traité par un bloc CATCH.

2voto

allprog Points 9189

El finally Le bloc fonctionne toujours. Soit vous return à l'intérieur du bloc try ou une exception est levée. L'exception levée dans le bloc finally remplacera celui lancé dans la branche catch.

De plus, le fait de lancer une exception ne provoque pas de sortie en soi. La ligne throw new Exception("2"); n'écrira rien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X