Domanda

Considerando questo codice, posso esserlo assolutamente sicuro che il finally block viene sempre eseguito, qualunque cosa accada something() È?

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

Soluzione

SÌ, finally verrà convocato dopo l'esecuzione dell' try O catch blocchi di codice.

Le uniche volte finally non verranno chiamati sono:

  1. Se invochi System.exit()
  2. Se la JVM si blocca prima
  3. Se la JVM raggiunge un ciclo infinito (o qualche altra istruzione non interrompibile e non terminante) nel file try O catch bloccare
  4. Se il sistema operativo termina forzatamente il processo JVM;per esempio., kill -9 <pid> su UNIX
  5. Se il sistema host muore;ad esempio, interruzione di corrente, errore hardware, panico del sistema operativo, eccetera
  6. Se la finally Il blocco verrà eseguito da un thread demone e tutti gli altri thread non demoni usciranno prima finally è chiamato

Altri suggerimenti

Codice di esempio:

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

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

Produzione:

finally trumps return. 
0

Inoltre, sebbene sia una cattiva pratica, se c'è un'istruzione return all'interno del blocco last, prevarrà su qualsiasi altro return dal blocco regolare.Cioè, il seguente blocco restituirebbe false:

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

Stessa cosa con il lancio di eccezioni dal blocco finale.

Ecco le parole ufficiali della specifica del linguaggio Java.

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

UN try dichiarazione con a finally il blocco viene eseguito eseguendo prima il file try bloccare.Poi c'è una scelta:

  • Se l'esecuzione del try il blocco si completa normalmente, [...]
  • Se l'esecuzione del try il blocco viene completato improvvisamente a causa di a throw di un valore V, [...]
  • Se l'esecuzione del try il blocco viene completato improvvisamente per qualsiasi altro motivo R, poi il finally il blocco viene eseguito.Poi c'è una scelta:
    • Se il blocco last viene completato normalmente, allora il file try l'affermazione si completa bruscamente per la ragione R.
    • Se la finally il blocco viene completato improvvisamente per un motivo S, poi il try l'affermazione si completa bruscamente per la ragione S (e ragione R viene scartato).

La specifica per return in realtà lo rende esplicito:

JLS 14.17 La dichiarazione di ritorno

ReturnStatement:
     return Expression(opt) ;

UN return dichiarazione con il n Expression tentativi per trasferire il controllo all'invocatore del metodo o al costruttore che lo contiene.

UN return dichiarazione con un Expression tentativi trasferire il controllo all'invocatore del metodo che lo contiene;il valore del Expression diventa il valore della chiamata del metodo.

Le descrizioni precedenti dicono "tentativi trasferire il controllo"piuttosto che semplicemente"controllo dei trasferimenti"perché se ce ne sono try istruzioni all'interno del metodo o del costruttore cui try i blocchi contengono il file return dichiarazione, quindi qualsiasi finally clausole di quelli try le istruzioni verranno eseguite, in ordine, dalla più interna alla più esterna, prima che il controllo venga trasferito all'invocatore del metodo o del costruttore.Completamento improvviso di a finally clausola può interrompere il trasferimento del controllo avviato da a return dichiarazione.

Oltre alle altre risposte, è importante sottolineare che 'finally' ha il diritto di sovrascrivere 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();
    }
}

Ho provato l'esempio sopra con una 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 restituisce:

finalmente torna la briscola.
2

Questo perché quando return i; viene eseguito i ha valore 2.Dopo questo il finally viene eseguito il blocco a cui è assegnato 12 i poi System.out out viene eseguito.

Dopo aver eseguito il finally bloccare il try il blocco restituisce 2, invece di restituire 12, perché questa istruzione return non viene eseguita nuovamente.

Se esegui il debug di questo codice in Eclipse, avrai la sensazione che dopo l'esecuzione System.out Di finally bloccare il return dichiarazione di try il blocco viene eseguito nuovamente.Ma non è così.Restituisce semplicemente il valore 2.

Ecco un'elaborazione di La risposta di Kevin.È importante sapere che l'espressione da restituire viene valutata prima finally, anche se viene restituito 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

Questa è l'idea stessa di un blocco definitivo.Ti consente di assicurarti di eseguire pulizie che altrimenti potrebbero essere saltate perché ritorni, tra le altre cose, ovviamente.

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

Un modo logico di pensare a questo è:

  1. Il codice inserito in un blocco final deve essere eseguito qualunque cosa accada all'interno del 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" finché il blocco finale non può essere eseguito
  3. Poiché il codice nel blocco last ha (per definizione) un'alta priorità, può restituire o lanciare ciò che vuole.In tal caso tutto ciò che rimane "sullo scaffale" viene scartato.
  4. L'unica eccezione a ciò è se la VM si spegne completamente durante il blocco try, ad es.da 'System.exit'

Anche un ritorno alla fine eliminerà ogni eccezione. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

infine viene sempre eseguito a meno che non si verifichi una chiusura anomala del programma (come la chiamata a System.exit(0)..).quindi il tuo sysout verrà stampato

Il blocco last viene sempre eseguito a meno che non si verifichi una chiusura anomala del programma, derivante da un arresto anomalo della JVM o da una chiamata a System.exit(0).

Oltre a ciò, qualsiasi valore restituito dall'interno del bloccofinal sovrascriverà il valore restituito prima dell'esecuzione del bloccofinalmente, quindi fai attenzione a controllare tutti i punti di uscita quando usi try finalmente.

No, non sempre un caso di eccezione è // System.Exit (0);prima che il blocco finale impedisca l'esecuzione definitiva.

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

Infine viene sempre eseguito, questo è il punto, solo perché appare nel codice dopo il ritorno non significa che sia così implementato.Il runtime Java ha la responsabilità di eseguire questo codice all'uscita dal file try bloccare.

Ad esempio, se hai quanto segue:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

Il runtime genererà qualcosa del genere:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Se viene lanciata un'eccezione non rilevata, il file finally il blocco verrà eseguito e l'eccezione continuerà a propagarsi.

Questo perché hai assegnato il valore di i come 12, ma non hai restituito il valore di i alla funzione.Il codice corretto è il seguente:

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

Perché un blocco last verrà sempre chiamato a meno che tu non chiami System.exit() (o il thread si blocca).

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

Sì, verrà chiamato.Questo è il punto centrale di avere una parola chiave finalmente.Se saltando fuori dal blocco try/catch si potesse semplicemente saltare il blocco final, sarebbe stato come mettere System.out.println fuori dal blocco try/catch.

In sintesi, nella documentazione ufficiale Java (Click Qui), è scritto che -

Se il JVM esce mentre viene eseguito il codice TRY o Catch, il blocco finalmente potrebbe non eseguire.Allo stesso modo, se il thread che esegue il codice try o catch viene interrotto o ucciso, il blocco finalmente potrebbe non eseguire anche se l'applicazione nel suo insieme continua.

Sì, finalmente il blocco viene sempre eseguito.La maggior parte degli sviluppatori utilizza questo blocco per chiudere la connessione al database, l'oggetto set di risultati, l'oggetto istruzione e lo utilizza anche nell'ibernazione Java per ripristinare la transazione.

Si lo farà.Non importa cosa succede nel tuo blocco try o catch, a meno che non venga chiamato altrimenti System.exit() o JVM si blocchi.se è presente un'istruzione return nei blocchi, verrà infine eseguita prima di tale istruzione return.

Si lo farà.L'unico caso in cui ciò non accadrà è che la JVM esca o si arresti in modo anomalo

Consideriamo 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());
        System.out.println("---PRINT THE RESULT---");
        System.out.println(sb.toString());
    }

    private static String someString() {

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

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

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

-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz

questo significa che usando finally 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; // Just an example, but you can close streams or DB connections this way.
    }
}

In realtà questo è vero in qualsiasi linguaggio...finalmente verrà sempre eseguito prima di un'istruzione return, indipendentemente da dove si trovi quel return nel corpo del metodo.Se così non fosse, il blocco finale non avrebbe molto significato.

finally eseguirà e questo è sicuro.

finally non verrà eseguito nei seguenti casi:

caso 1 :

Quando stai eseguendo System.exit().

caso 2:

Quando la tua JVM/Thread si blocca.

caso 3:

Quando l'esecuzione viene interrotta manualmente.

Se non gestisci l'eccezione, prima di terminare il programma, JVM esegue infine il blocco.Non verrà eseguito solo se la normale esecuzione del programma fallirà significando la chiusura del programma a causa dei seguenti motivi.

  1. Causando un errore fatale che causa l'interruzione del processo.

  2. Interruzione del programma a causa di memoria danneggiata.

  3. Chiamando System.exit()

  4. Se il programma entra in ciclo infinito.

Si perchè nessuna dichiarazione di controllo può prevenire finally dall'essere giustiziato.

Ecco un esempio di riferimento, in cui verranno eseguiti tutti i blocchi di codice:

| x | Current result | Code 
|---|----------------|------ - - -
|   |                |     
|   |                | public static int finallyTest() {
| 3 |                |     int x = 3;
|   |                |     try {
|   |                |        try {
| 4 |                |             x++;
| 4 | return 4       |             return x;
|   |                |         } finally {
| 3 |                |             x--;
| 3 | throw          |             throw new RuntimeException("Ahh!");
|   |                |         }
|   |                |     } catch (RuntimeException e) {
| 4 | return 4       |         return ++x;
|   |                |     } finally {
| 3 |                |         x--;
|   |                |     }
|   |                | }
|   |                |
|---|----------------|------ - - -
|   | Result: 4      |

Nella variante sottostante, return x; verrà saltato.Il risultato è ancora 4:

public static int finallyTest() {
    int x = 3;
    try {
        try {
            x++;
            if (true) throw new RuntimeException("Ahh!");
            return x; // skipped
        } finally {
            x--;
        }
    } catch (RuntimeException e) {
        return ++x;
    } finally {
        x--;
    }
}

I riferimenti, ovviamente, tengono traccia del loro stato.Questo esempio restituisce un riferimento con value = 4:

static class IntRef { public int value; }
public static IntRef finallyTest() {
    IntRef x = new IntRef();
    x.value = 3;
    try {
        return x;
    } finally {
        x.value++; // will be tracked even after return
    }
}

try- catch- finally sono le parole chiave per l'utilizzo del caso di gestione delle eccezioni.
Come normale spiegazione

try {
     //code statements
     //exception thrown here
     //lines not reached if exception thrown
} catch (Exception e) {
    //lines reached only when exception is thrown
} finally {
    // always executed when the try block is exited
    //independent of an exception thrown or not
}

Il blocco finale impedisce l'esecuzione...

  • Quando hai chiamato System.exit(0);
  • Se JVM esce.
  • Errori nella JVM

Aggiunta a La risposta di @vibhash poiché nessun'altra risposta spiega cosa succede nel caso di un oggetto mutabile come quello qui sotto.

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

public static StringBuffer test() {
    StringBuffer s = new StringBuffer();
    try {
        s.append("sb");
        return s;
    } finally {
        s.append("updated ");
    }
}

Uscirà

sbupdated 

Ho provato questo, è un singolo filo.

class Test {
    public static void main(String args[]) throws Exception {
       Object obj = new Object();
       try {
            synchronized (obj) {
            obj.wait();
            System.out.println("after wait()");
           }
       } catch (Exception e) {
       } finally {
           System.out.println("finally");
       }
   }
}

Il thread principale sarà in stato di attesa per sempre, quindi alla fine non verrà mai chiamato,

quindi l'output della console non stamperà la stringa: after wait() O finally

D'accordo con @Stephen C, l'esempio sopra è uno dei terzi casi menzionati Qui:

Aggiungendo altre possibilità di loop infinito nel seguente codice:

// import java.util.concurrent.Semaphore;
class Test {
    public static void main(String[] args) {
        try {
            // Thread.sleep(Long.MAX_VALUE);
            // Thread.currentThread().join();
            // new Semaphore(0).acquire();
            // while (true){}
            System.out.println("after sleep join semaphore exit infinite while loop");
        } catch (Exception e) {
        } finally {
            System.out.println("finally");
        }
    }
}

Caso 2:Se la JVM si blocca prima

import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Test {
    public static void main(String args[]) {
        try {
            unsafeMethod();
//            Runtime.getRuntime().halt(123);
            System.out.println("After Jvm Crash!");
        } catch (Exception e) {
        } finally {
            System.out.println("finally");
        }
    }

    private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        unsafe.putAddress(0, 0);
    }
}

Rif: Come si blocca una JVM?

Caso 6:Se finalmente il blocco verrà eseguito dal thread demone e tutti gli altri thread non demoni escono prima che venga chiamato finalmente.

class Test {
    public static void main(String args[]) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    printThreads("Daemon Thread printing");
                    // just to ensure this thread will live longer than main thread
                    Thread.sleep(10000);
                } catch (Exception e) {
                } finally {
                    System.out.println("finally");
                }
            }
        };
        Thread daemonThread = new Thread(runnable);
        daemonThread.setDaemon(Boolean.TRUE);
        daemonThread.setName("My Daemon Thread");
        daemonThread.start();
        printThreads("main Thread Printing");
    }

    private static synchronized void printThreads(String str) {
        System.out.println(str);
        int threadCount = 0;
        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
        for (Thread t : threadSet) {
            if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
                System.out.println("Thread :" + t + ":" + "state:" + t.getState());
                ++threadCount;
            }
        }
        System.out.println("Thread count started by Main thread:" + threadCount);
        System.out.println("-------------------------------------------------");
    }
}

produzione:Questo non stampa "finalmente", il che implica che "Finalmente blocca" nel "thread demone" non è stato eseguito

main Thread Printing  
Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED  
Thread :Thread[main,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE   
Thread count started by Main thread:3  
-------------------------------------------------  
Daemon Thread printing  
Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE  
Thread count started by Main thread:2  
-------------------------------------------------  

Process finished with exit code 0
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top