Czy blok ostatecznie działa, nawet jeśli wyrzucisz nowy wyjątek?

142

W tym kodzie zostanie someVarustawiony, nawet jeśli zostanie wykonany blok catch i zostanie zgłoszony drugi wyjątek?

public void someFunction() throws Exception {
    try {
        //CODE HERE
    } catch (Exception e) {
        Log.e(TAG, "", e);
        throw new Exception(e);
    } finally {
        this.someVar= true;
    }
}
jax
źródło
2
Ponieważ istnieją okoliczności, w których zachowanie nie jest zgodne z oczekiwaniami, na co wskazuje @GaryF
jax,
1
Warto zauważyć, że ostatni blok może nie zostać wykonany zgodnie z oczekiwaniami, jeśli zgłosi wyjątek lub zwróci.
Peter Lawrey

Odpowiedzi:

184

Tak, ostatnie bloki zawsze działają ... z wyjątkiem sytuacji, gdy:

  • Wątek uruchamiający blok try-catch-final zostaje zabity lub przerwany
  • Używasz System.exit(0);
  • Bazowa maszyna wirtualna jest niszczona w inny sposób
  • Podstawowy sprzęt jest w jakiś sposób bezużyteczny

Dodatkowo, jeśli metoda w twoim bloku last zgłosi nieprzechwycony wyjątek, to nic po nim nie zostanie wykonane (tj. Wyjątek zostanie wyrzucony tak, jak w każdym innym kodzie). Bardzo częstym przypadkiem, w którym to się dzieje, jest java.sql.Connection.close().

Na marginesie, zgaduję, że przykładowy kod, którego użyłeś, jest tylko przykładem, ale uważaj, aby umieścić rzeczywistą logikę w bloku final. Ostatni blok jest przeznaczony do czyszczenia zasobów (zamykanie połączeń z bazą danych, zwalnianie uchwytów plików itp.), A nie do logiki, która musi być uruchomiona. Jeśli musi być uruchomiony, zrób to przed blokiem try-catch, z dala od czegoś, co mogłoby zgłosić wyjątek, ponieważ Twoja intencja jest prawie na pewno funkcjonalnie taka sama.

GaryF
źródło
4
Co masz na myśli, mówiąc „Wątek uruchamiający blok try-catch-last jest [...] przerwany”? Być może dokumentacja jest słabo sformułowana, ale Thread.interrupt () nie spowoduje pominięcia ostatniego bloku, niezależnie od tego, czy zostanie wyrzucony z bloku try, czy catch. Czy to słowo „przerwano” oznacza coś bardziej brutalnego, jak Thread.stop ()?
Joe Kearney
@Joe: Tak, myślę, że dokumentacja jest tutaj trochę źle sformułowana i że oznaczają one ogólne zakłócenie działalności wątku.
GaryF,
@GaryF - Myślę, że cytujesz z JLS. Sformułowanie JLS jest czasami nieco dziwne, ale zwykle zauważysz, że znaczenie dziwnej terminologii jest jasno zdefiniowane w innym miejscu dokumentu. JLS to specyfikacja, której głównym celem jest precyzja (a nie czytelność).
Stephen C
1
@Stephen C - Właściwie to pochodzi z samouczka JavaSE (do którego prowadzą inni). Może to być podobnie sformułowane w JLS, ale nie mogę znaleźć odpowiedniej części. Spodziewałbym się tego w rozdziale 11 (Wyjątki), rozdziale 14 (Instrukcje) lub rozdziale 15 (Wyrażenia), ale nie widzę niczego, co odnosi się bezpośrednio do przerw. Z pewnością chciałbym to zobaczyć.
GaryF
1
@GaryF - rozumiem. W rzeczywistości JLS mówi o „normalnym” i „nagłym” kończeniu instrukcji i jest sekcja (14.1), która definiuje terminologię. Zachowanie finallyjest następnie określane jako normalne i nagłe zakończenie.
Stephen C
10

Tak.

Zobacz dokumentację :

Ostatni blok jest zawsze wykonywany, gdy blok try kończy działanie.

Wyjątki:

Uwaga: Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final może nie zostać wykonany. Podobnie, jeśli wątek wykonujący kod try lub catch zostanie przerwany lub zabity, ostatni blok może nie zostać wykonany, mimo że aplikacja jako całość będzie kontynuowana.

froadie
źródło
2

Wreszcie blok zawsze jest wykonywany.

public class ExceptionTest {

public static void someFunction(String input) throws Exception {
    try {
        if( input.equals("ABC") ) {
            System.out.println("Matched");
        }
    } catch (Exception e) {
        throw new Exception(e);
    } finally {
        System.out.println("Input Is "+input+" Finally Executed!!!");
    }
}

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    try {
        System.out.println("********* Test with VALUE ********* ");
        someFunction("ABC");
        System.out.println("\r\n********* Test with NULL  ********* ");
        someFunction(null);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

Java Try Catch Final Block with Throw

Vasanth Umapathy
źródło
2

Wreszcie jest zawsze wykonywany, bez względu na to, jaki jest twój przypadek, tj

  • blok try-catch-last
  • rzuca

W przypadku niezaznaczonych wyjątków java nie upoważnia do obsługi błędów. z tego powodu, jeśli niesprawdzony wyjątek wystąpi w ostatnim bloku to i nie zostanie wykonana żadna obsługa, kod zapisany poniżej tego punktu (w którym wystąpił błąd) nie zostanie wykonany.

Dlatego sugeruję, aby zawsze obsługiwać wszystkie wyjątki, może być zaznaczone lub odznaczone. W ten sposób możesz upewnić się, że blok kodu w końcu zostanie również wykonany, bez względu na to, czy wystąpi również niezaznaczony wyjątek. masz miejsce w złowieniu pod gniazdem i wreszcie blok, aby wykonać niezbędną pracę.

yug
źródło
1

Tak. finallyblok jest wykonywany zawsze z wyjątkiem przypadku wywołania System.exit (), ponieważ zatrzymuje maszynę wirtualną Java.

Vladimir Ivanov
źródło
Haki zamykające są nadal wywoływane po funkcji System.exit (), ale wszystkie istniejące wątki niesystemowe są zatrzymywane.
Peter Lawrey,