non - try finally java




Un blocco finally viene sempre eseguito in Java? (20)

La risposta è semplice .

INGRESSO:

try{
    int divideByZeroException = 5 / 0;
} catch (Exception e){
    System.out.println("catch");
    return;    // also tried with break; in switch-case, got same output
} finally {
    System.out.println("finally");
}

PRODUZIONE:

catch
finally

Considerando questo codice, posso essere assolutamente sicuro che il blocco finally viene sempre eseguito, indipendentemente da qual'è something() ?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("i don't know if this will get printed out.");
}


Concisamente, nella documentazione ufficiale di Java (clicca here ), è scritto che -

Se la JVM termina mentre viene eseguito il codice try o catch, allora il blocco finally potrebbe non essere eseguito. Allo stesso modo, se il thread che esegue il codice try o catch viene interrotto o ucciso, il blocco finally potrebbe non essere eseguito anche se l'applicazione continua nel suo complesso.


Considera il seguente programma:

public class someTest {

    private static StringBuilder sb = new StringBuilder();

    public static void main(String args[]) {

        System.out.println(someString());
        System.out.println("---AGAIN---");
        System.out.println(someString());
    }

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

A partire da Java 1.8.162, il precedente blocco di codice fornisce il seguente output:

-abc-
---AGAIN---
-abc-xyz-abc-

questo significa che usare finally per liberare oggetti è una buona pratica come il seguente codice:

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null;
    }
}

Ecco le parole ufficiali della specifica del linguaggio Java.

14.20.2. Esecuzione di try-finally e try-catch-finally

Un'istruzione try con un blocco finally viene eseguita eseguendo prima il blocco try . Quindi c'è una scelta:

  • Se l'esecuzione del blocco try completata normalmente, [...]
  • Se l'esecuzione del blocco try completata improvvisamente a causa di un throw di un valore V , [...]
  • Se l'esecuzione del blocco try termina bruscamente per qualsiasi altra ragione R , viene eseguito il blocco finally . Quindi c'è una scelta:
    • Se il blocco finally viene completato normalmente, l'istruzione try completata improvvisamente per la ragione R.
    • Se il blocco finally termina bruscamente per la ragione S , allora l'istruzione try conclude bruscamente per la ragione S ( e la ragione R viene scartata ).

Le specifiche per il return realtà rendono esplicito questo:

JLS 14.17 Dichiarazione di reso

ReturnStatement:
     return Expression(opt) ;

Un'istruzione return senza Expression tenta di trasferire il controllo al invoker del metodo o costruttore che lo contiene.

Una dichiarazione di return con Expression tenta di trasferire il controllo all'invocatore del metodo che lo contiene; il valore Expression diventa il valore dell'invocazione del metodo.

Le descrizioni precedenti dicono " tentativi di trasferire il controllo " piuttosto che " controlli di trasferimento " perché se ci sono delle istruzioni di try all'interno del metodo o costruttore i cui blocchi di try contengono l'istruzione return , allora verranno eseguite tutte le clausole finali di quelle try , in ordine, da più interno a più esterno, prima che il controllo venga trasferito all'invocatore del metodo o costruttore. Il completamento brusco di una clausola finally può interrompere il trasferimento del controllo avviato da una dichiarazione di return .


Ecco un'elaborazione della risposta di Kevin . È importante sapere che l'espressione da restituire viene valutata prima finally , anche se viene restituita dopo.

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int printX() {
    System.out.println("X");
    return 0;
}

public static int test() {
    try {
        return printX();
    }
    finally {
        System.out.println("finally trumps return... sort of");
    }
}

Produzione:

X
finally trumps return... sort of
0

Ho provato l'esempio sopra con leggera modifica-

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

Il codice sopra riportato produce:

finalmente briscola ritorno.
2

Questo perché quando return i; viene eseguito i ha un valore 2. Dopodiché viene eseguito il blocco finally cui 12 viene assegnato a i e quindi viene eseguito System.out out.

Dopo aver eseguito il blocco finally blocco try restituisce 2, anziché restituire 12, perché questa dichiarazione di ritorno non viene eseguita nuovamente.

Se esegui il debug di questo codice in Eclipse, avrai la sensazione che dopo l'esecuzione di System.out di finally block l'istruzione return di try block venga eseguita nuovamente. Ma questo non è il caso. Restituisce semplicemente il valore 2.


Il blocco finally viene sempre eseguito a meno che non vi sia una terminazione anomala del programma, risultante da un arresto anomalo di JVM o da una chiamata a System.exit(0) .

Inoltre, qualsiasi valore restituito dall'interno del blocco finally sovrascriverà il valore restituito prima dell'esecuzione del blocco finally, quindi fai attenzione a controllare tutti i punti di uscita quando utilizzi try finally.


Inoltre, anche se è una cattiva pratica, se c'è un'istruzione return nel blocco finally, vincerà qualsiasi altro return dal blocco regolare. Cioè, il seguente blocco restituirebbe falso:

try { return true; } finally { return false; }

Stessa cosa con il lancio di eccezioni dal blocco finale.


No, non sempre un caso di eccezione è // System.exit (0); prima che il blocco finalmente impedisca di essere finalmente eseguito.

  class A {
    public static void main(String args[]){
        DataInputStream cin = new DataInputStream(System.in);
        try{
            int i=Integer.parseInt(cin.readLine());
        }catch(ArithmeticException e){
        }catch(Exception e){
           System.exit(0);//Program terminates before executing finally block
        }finally{
            System.out.println("Won't be executed");
            System.out.println("No error");
        }
    }
}

Oltre alle altre risposte, è importante sottolineare che "finally" ha il diritto di ignorare qualsiasi eccezione / valore restituito dal blocco try..catch. Ad esempio, il codice seguente restituisce 12:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

Allo stesso modo, il seguente metodo non genera un'eccezione:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

Mentre il seguente metodo lo lancia:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}

Perché la finale è sempre chiamata in qualunque caso tu abbia. Non hai eccezioni, è ancora chiamato, cattura l'eccezione, è ancora chiamato


Questa è l'idea di un blocco finale. Ti permette di assicurarti di eseguire delle pulizie che altrimenti potrebbero essere saltate perché tu ritorni, tra le altre cose, ovviamente.

Alla fine viene chiamato indipendentemente da ciò che accade nel blocco try (a meno che non si chiami System.exit(int) o Java Virtual Machine venga System.exit(int) per qualche altro motivo).


Questo è vero in ogni lingua ... alla fine verrà sempre eseguito prima di una dichiarazione di ritorno, indipendentemente da dove si trovi quel ritorno nel corpo del metodo. Se così non fosse, il blocco finale non avrebbe molto significato.


Sì, alla finally verrà chiamato dopo l'esecuzione dei blocchi try o catch code.

Le uniche volte che finally non verranno chiamate sono:

  1. Se invochi System.exit() ;
  2. Se la JVM si arresta prima
  3. Se la JVM raggiunge un ciclo infinito (o qualche altra istruzione non interrompibile e non terminante) nel blocco try o catch ;
  4. Se il sistema operativo termina forzatamente il processo JVM; ad esempio "kill -9" su UNIX.
  5. Se il sistema host muore; es. mancanza di corrente, errore hardware, panico del sistema operativo, eccetera.
  6. Se finalmente il blocco verrà eseguito dal thread daemon e tutti gli altri thread non daemon escono prima che venga finalmente chiamato.

Sì, finalmente il blocco è sempre eseguito. La maggior parte degli sviluppatori usa questo blocco chiudendo la connessione al database, l'oggetto resultset, l'oggetto statement e anche gli usi in hibernate java per eseguire il rollback della transazione.


Se viene lanciata un'eccezione, alla fine viene eseguito. Se non viene lanciata un'eccezione, alla fine viene eseguito. Se viene rilevata l'eccezione, viene infine eseguito. Se l'eccezione non viene rilevata, viene finalmente eseguita.

L'unica volta che non viene eseguito è quando si esce da JVM.


Si lo farà. Non importa cosa succede nel tuo try o catch block a meno che System.exit () non chiami o JVM si arresti. se c'è qualche dichiarazione di ritorno nel blocco (s), finalmente sarà eseguito prima di quella dichiarazione di ritorno.


Un modo logico per pensarci è:

  1. Il codice inserito in un blocco finally deve essere eseguito qualunque cosa si verifichi nel blocco try
  2. Quindi, se il codice nel blocco try tenta di restituire un valore o lanciare un'eccezione, l'elemento viene posizionato 'sullo scaffale' fino a quando il blocco finally può essere eseguito
  3. Poiché il codice nel blocco finally ha (per definizione) un'alta priorità, può restituire o lanciare qualsiasi cosa gli piaccia. In tal caso, qualsiasi cosa lasciata sullo scaffale viene scartata.
  4. L'unica eccezione a questo è se la VM si spegne completamente durante il blocco try, ad es. Con 'System.exit'

Un modo logico per pensarci è:

Il codice inserito in un blocco finally deve essere eseguito qualunque cosa si verifichi nel blocco try.

Quindi, se il codice nel blocco try tenta di restituire un valore o lanciare un'eccezione, l'elemento viene posto 'sullo scaffale' finché il blocco finally può essere eseguito Perché il codice nel blocco finally ha (per definizione) un'alta priorità che può restituire o lanciare qualunque cosa voglia. In tal caso, qualsiasi cosa lasciata sullo scaffale viene scartata.

L'unica eccezione a questo è se la VM si spegne completamente durante il blocco try, ad es. Con 'System.exit'

Non lanciare mai alcuna eccezione dal blocco finale

try {
  someMethod();  //Throws exceptionOne
} finally {
  cleanUp();    //If finally also threw any exception the exceptionOne will be lost forever
}

Questo va bene, purché cleanUp () non possa mai generare eccezioni. Nell'esempio precedente, se someMethod () genera un'eccezione e anche nel blocco finally, cleanUp () genera un'eccezione, la seconda eccezione verrà fuori dal metodo e la prima eccezione originale (motivo corretto) verrà persa per sempre. Se il codice che si chiama in un blocco finally può generare un'eccezione, assicurarsi di gestirlo o registrarlo. Non lasciarlo mai uscire dal blocco finale.

In realtà, l'uscita dal programma (chiamando System.exit () o provocando un errore irreversibile che causa l'abortire del processo: a volte indicato in modo informale come "hotspot" o "Dr Watson" in Windows) impedirà di bloccare definitivamente il blocco eseguito!

Non c'è niente che ci impedisca di annidare i blocchi try / catch / finally (ad esempio, mettendo un blocco try / finally all'interno di un blocco try / catch, o viceversa), e non è una cosa così rara da fare.





try-catch-finally