Wyjątek wyrzucony wewnątrz bloku catch - czy zostanie złapany ponownie?

To może wydawać się pytaniem o programming 101 i myślałem, że znam odpowiedź, ale teraz muszę to sprawdzić. Czy w poniższym fragmencie kodu wyjątek rzucony w pierwszym bloku catch zostanie przechwycony przez ogólny blok catch Exception poniżej?

try {
  // Do something
} catch(IOException e) {
  throw new ApplicationException("Problem connecting to server");
} catch(Exception e) {
  // Will the ApplicationException be caught here?
}

Zawsze myślałem, że odpowiedź będzie nie, ale teraz mam dziwne zachowanie, które może być spowodowane przez to. Odpowiedź jest prawdopodobnie taka sama dla większości języków, ale pracuję w Javie.

Author: Jeff Mercado, 2008-09-27

9 answers

Nie, ponieważ nowy {[0] } nie znajduje się bezpośrednio w bloku try.

 235
Author: Chris Jester-Young,
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
2008-09-27 13:13:30

Nie. Bardzo łatwo to sprawdzić.

public class Catch {
    public static void main(String[] args) {
        try {
            throw new java.io.IOException();
        } catch (java.io.IOException exc) {
            System.err.println("In catch IOException: "+exc.getClass());
            throw new RuntimeException();
        } catch (Exception exc) {
            System.err.println("In catch Exception: "+exc.getClass());
        } finally {
            System.err.println("In finally");
        }
    }
}

Powinien wydrukować:

In catch IOException: class java.io.IOException
In finally
Exception in thread "main" java.lang.RuntimeException
        at Catch.main(Catch.java:8)

Technicznie mógł to być błąd kompilatora, zależne od implementacji, nieokreślone zachowanie, czy coś. Jednak JLS jest dość dobrze przybity i kompilatory są wystarczająco dobre do tego rodzaju prostych rzeczy (generics corner case może być inna sprawa).

Zauważ również, że jeśli zamienisz dwa bloki catch, nie będzie kompilacji. Drugi połów byłby całkowicie nieosiągalny.

Uwaga blok finally zawsze działa, nawet jeśli blok catch jest wykonywany (inne niż głupie przypadki, takie jak nieskończone pętle, dołączanie przez interfejs narzędzi i zabijanie wątku, przepisywanie kodu bajtowego itp.).

 74
Author: Tom Hawtin - tackline,
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
2015-02-18 19:32:47

Specyfikacja języka Java mówi w sekcji 14.19.1:

Jeśli wykonanie bloku try zakończy się nagle z powodu wyrzucenia wartości V, wtedy jest wybór:

  • Jeśli typ run-time V jest przypisany do parametru dowolnej klauzuli catch instrukcji try, wtedy wybrana jest pierwsza (po lewej stronie) taka klauzula catch. Wartość V jest przypisana do parametru wybranej klauzuli catch, a Blok tej klauzuli catch jest wykonywany. Jeśli ten blok polecenie TRY kończy się normalnie; jeśli blok kończy się nagle z jakiegokolwiek powodu, to polecenie TRY kończy się nagle z tego samego powodu.

Odniesienie: http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

Innymi słowy, pierwszy połów, który może obsłużyć wyjątek, robi, a jeśli wyjątek zostanie wyrzucony z tego połowu, nie jest to w zakresie żadnego innego połowu dla oryginalna próba, więc nie będą próbować sobie z tym poradzić.

Jedną z powiązanych i mylących rzeczy jest to, że w strukturze try-[catch] - finally blok może rzucić wyjątek, a jeśli tak, każdy wyjątek wyrzucony przez blok try lub catch jest tracony. To może być mylące, gdy pierwszy raz to widzisz.

 28
Author: Alex Miller,
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
2020-06-20 09:12:55

Jeśli chcesz wyrzucić wyjątek z bloku catch, musisz poinformować o tym swoją metodę / klasę / etc. że musi rzucić wspomniany wyjątek. Tak:

public void doStuff() throws MyException {
    try {
        //Stuff
    } catch(StuffException e) {
        throw new MyException();
    }
}

A teraz twój kompilator nie będzie na Ciebie krzyczał:)

 6
Author: Mastergeek,
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-06-14 14:52:51

Nie -- jak powiedział Chris Jester-Young, zostanie wyrzucony do następnej próby-złapać w hierarchii.

 4
Author: Ian P,
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
2008-09-27 13:15:31

Jak wspomniano powyżej...
Dodam, że jeśli masz problemy z widzeniem, co się dzieje, jeśli nie możesz odtworzyć problemu w debuggerze, możesz dodać ślad przed ponownym wyrzuceniem nowego wyjątku (z dobrym starym systemem.Wynocha.println w gorszym, z dobrym systemem logowania jak log4j inaczej).

 2
Author: PhiLho,
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
2008-09-27 13:38:34

Nie zostanie złapany przez drugi blok. Każdy wyjątek jest przechwytywany tylko w bloku try. Można jednak zagnieżdżać (Nie żeby to był ogólnie dobry pomysł):

try {
    doSomething();
} catch (IOException) {
   try {
       doSomething();
   } catch (IOException e) {
       throw new ApplicationException("Failed twice at doSomething" +
       e.toString());
   }          
} catch (Exception e) {
}
 2
Author: Vinko Vrsalovic,
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
2008-09-27 13:53:35

Nie, ponieważ wszystkie połowy odnoszą się do tego samego bloku try, więc rzucanie z wewnątrz bloku catch byłoby przechwytywane przez zamknięty blok try (prawdopodobnie w metodzie, która nazwała ten)

 1
Author: Uri,
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
2008-09-27 22:05:17

Stary post ale zmienna " e " musi być unikalna:

try {
  // Do something
} catch(IOException ioE) {
  throw new ApplicationException("Problem connecting to server");
} catch(Exception e) {
  // Will the ApplicationException be caught here?
}
 -4
Author: Ted K,
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-12-01 04:47:45