Wyjątek Javy nie został złapany?

Mam mały teoretyczny problem z konstrukcjami try-catch.

Wczoraj zdałem egzamin praktyczny na temat Javy i nie rozumiem poniższego przykładu:

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

Pytanie brzmiało: "jak będzie wyglądał wynik?"

Byłem prawie pewien, że będzie to AB2C3, ale niespodzianka niespodzianka, to nieprawda.

Właściwą odpowiedzią jest ABC3(testowany i tak naprawdę jest).

Moje pytanie brzmi, gdzie poszedł wyjątek("2")?

Author: Kousalik, 2013-08-07

6 answers

Ze specyfikacji języka Java 14.20.2.:

Jeśli blok catch zakończy się nagle z powodu R, to blok finally zostanie wykonany. Wtedy jest wybór:

  • Jeśli blok finally zakończy się normalnie, Instrukcja TRY zakończy się nagle z powodu r.

  • Jeśli blok finally zakończy się nagle z powodu s, to Instrukcja try zakończy się nagle z powodu s (a przyczyna R jest odrzucone) .

Więc, gdy jest blok catch, który rzuca wyjątek:

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

Ale jest też blok finally, który również rzuca wyjątek:

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

Exception("2") zostaną odrzucone i tylko Exception("3") będą propagowane.

 195
Author: Adam Siemion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-17 13:01:11

Wyjątki rzucone w bloku finally block tłumią wyjątek rzucony wcześniej w bloku try lub catch.

Java 7 przykład: http://ideone.com/0YdeZo

Z Javadoc ' s przykład:


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

Jednak w tym przykładzie, jeśli metody readLine I close oba rzucają WYJĄTKÓW, wtedy metoda readFirstLineFromFileWithFinallyblock rzuca wyjątek wyrzucony z bloku finally; wyjątek wyrzucony z bloku try jest stłumiony.


Nowa składnia try-with Java 7 dodaje kolejny krok eliminowania WYJĄTKÓW: wyjątki rzucone w bloku try tłumią te rzucone wcześniej w części try-with.

Z tego samego przykładu:

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

Wyjątek może być wyrzucony z bloku kodu związanego z try-with-resources oświadczenie. W powyższym przykładzie wyjątek może być wyrzucone z bloku try, a do dwóch WYJĄTKÓW mogą być wyrzucane z try-with-resources oświadczenie, gdy próbuje zamknąć Obiekty ZipFile i BufferedWriter. Jeśli wyjątek zostanie wyrzucony z try block i jeden lub więcej wyjątków jest wyrzucanych z try-with-resources, wtedy te wyjątki wyrzucone z instrukcje try-with-resources są tłumione, a wyjątek wyrzucany przez blok jest ten, który jest wyrzucany przez metoda writeToFileZipFileContents. Możesz odzyskać te stłumione wyjątki wywołując Throwable.metoda getSuppressed z wyjątek rzucony przez blok try.


W kodzie z question, każdy blok wyraźnie odrzuca stary wyjątek, nawet go nie loguje, nie jest to dobre, gdy próbujesz rozwiązać niektóre błędy:

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

 19
Author: S.D.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-08 08:26:13

Ponieważ {[1] } jest wyrzucany z catch bloku, a nie try, nie zostanie ponownie złapany.
Zob. 14.20.2. Wykonanie try-finally I try-catch-finally.

Oto co się dzieje:

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
Author: Maroun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-08 07:00:39

Twoje pytanie jest bardzo oczywiste, a odpowiedź jest prosta w tym samym stopniu.. obiekt wyjątku z wiadomością jako " 2 "jest nadpisywany przez obiekt wyjątku z wiadomością jako" 3".

Explanation: Gdy wystąpi wyjątek, jego obiekt rzuca się złapać blok do obsługi. Ale gdy wyjątek występuje w samym bloku catch, jego obiekt jest przenoszony do zewnętrznego bloku CATCH (jeśli istnieje) w celu obsługi wyjątków. I to samo stało się tutaj. Obiekt Exception z Komunikatem "2" zostaje przeniesione do zewnętrznego bloku zaczepu . ale czekaj .. Przed opuszczeniem wewnętrznego bloku try-catch musi on w końcu wykonać. Tutaj nastąpiła zmiana, o którą się martwimy. Zostanie wyrzucony nowy obiekt wyjątku(z wiadomością "3") lub ten ostatecznie blok, który zastąpił już wyrzucony obiekt wyjątku (z wiadomością "2").w wyniku czego , podczas wypisywania wiadomości obiektu wyjątku, otrzymaliśmy nadpisaną wartość tzn. "3" a nie "2".

Pamiętaj :tylko jeden obiekt wyjątku może być / align = "left" /

 4
Author: Bharat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-07 13:57:01

Blok finally zawsze działa. Albo ty return z wewnątrz bloku try, albo wyjątek jest wyrzucany. Wyjątek rzucony w bloku finally nadpisze wyjątek rzucony w gałęzi catch.

Dodatkowo, wyrzucenie wyjątku nie spowoduje żadnego wyjścia. Linia throw new Exception("2"); niczego nie napisze.

 2
Author: allprog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-07 07:51:08

Według Twojego kodu:

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

Jak widać tutaj:

  1. print A and throws exception # 1;
  2. ten wyjątek został przechwycony przez polecenie catch i wydrukuj B - # 2;
  3. block finally # 3 wykonuje polecenie try-catch (lub tylko try, jeśli nie wystąpił żaden wyjątek) i wypisuje C - # 4 i wyrzuca nowy wyjątek;
  4. ten został złapany przez zewnętrzne stwierdzenie catch # 5;

Wynik to ABC3. I 2 jest pominięte w tak samo jak 1

 0
Author: nazar_art,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-13 22:40:24