Quali sono le circostanze in cui un blocco finally {} NON verrà eseguito?

In un try{} ... catch{} ... finally{} Java try{} ... catch{} ... finally{} , il codice all’interno di finally{} è generalmente considerato “garantito” per essere eseguito indipendentemente da ciò che accade nel try / catch. Tuttavia, so di almeno due circostanze in cui non verrà eseguito:

  • Se viene chiamato System.exit(0) ; o,
  • se viene lanciata un’eccezione fino alla JVM e si verifica il comportamento predefinito (ad esempio, printStackTrace() e exit)

Esistono altri comportamenti del programma che impediscono l’esecuzione del codice in un blocco finally{} ? In quali condizioni specifiche verrà eseguito il codice o no?

EDIT: come evidenziato da NullUserException, il secondo caso non è vero. Ho pensato che fosse perché il testo in errore standard è stato stampato dopo quello standard, impedendo la visualizzazione del testo senza scorrere verso l’alto. 🙂 Scuse.

Se si chiama System.exit() il programma si chiude immediatamente senza essere chiamato finally .

Un Crash JVM, ad esempio Segmentation Fault, impedirà anche di essere chiamato. cioè la JVM si ferma immediatamente a questo punto e produce un rapporto di crash.

Un ciclo infinito impedirebbe anche la chiamata definitiva.

Il blocco finally viene sempre chiamato quando viene lanciato un Throwable. Anche se chiami Thread.stop () che triggers un ThreadDeath da gettare nel thread di destinazione. Questo può essere catturato (è un Error ) e verrà chiamato il blocco finally.


 public static void main(String[] args) { testOutOfMemoryError(); testThreadInterrupted(); testThreadStop(); testStackOverflow(); } private static void testThreadStop() { try { try { final Thread thread = Thread.currentThread(); new Thread(new Runnable() { @Override public void run() { thread.stop(); } }).start(); while(true) Thread.sleep(1000); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testThreadInterrupted() { try { try { final Thread thread = Thread.currentThread(); new Thread(new Runnable() { @Override public void run() { thread.interrupt(); } }).start(); while(true) Thread.sleep(1000); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testOutOfMemoryError() { try { try { List bytes = new ArrayList(); while(true) bytes.add(new byte[8*1024*1024]); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testStackOverflow() { try { try { testStackOverflow0(); } finally { System.out.print("finally called after "); } } catch (Throwable t) { System.out.println(t); } } private static void testStackOverflow0() { testStackOverflow0(); } 

stampe

 finally called after java.lang.OutOfMemoryError: Java heap space finally called after java.lang.InterruptedException: sleep interrupted finally called after java.lang.ThreadDeath finally called after java.lang.StackOverflowError 

Nota: in ogni caso il thread continuava a funzionare, anche dopo SO, OOME, Interrupted e Thread.stop ()!

Ciclo infinito nel blocco try .

RAM danneggiata ? Il programma non funziona più come scritto? In realtà ho eseguito il debug di quella volta su una macchina DOS.

C’è una possibilità di esecuzione parziale quando finalmente essa stessa lancia un’eccezione (o porta a un errore)

Uno potrebbe essere “Alla fine è una parte del thread daeomon che potrebbe non essere eseguita”.

Le uniche volte che finalmente non verranno chiamate sono:

se il potere si spegne

  1. se chiami System.exit ()
  2. se la JVM si arresta prima
  3. se c’è un ciclo infinito nel blocco try
  4. se il potere si spegne

Testare il blocco finally in diverse istruzioni nel blocco try.

  public static void main(String [] args){ try{ System.out.println("Before Statement"); /*** Statement ***/ System.out.println("After Statement"); } catch(Exception e){ } finally{ System.out.println("Finally is Executed"); } 

Le dichiarazioni in cui il blocco finally viene eseguito sono le seguenti:

  1. Thread.currentThread().interrupted();
  2. Thread.currentThread().destroy();
  3. Thread.currentThread().stop();
  4. Thread.sleep(10);
  5. Thread.currentThread().interrupt();
  6. Runtime.getRuntime().addShutdownHook(Thread.currentThread());
  7. Se c’è qualche eccezione si è verificato.
  8. Se non c’è eccezione.

Le dichiarazioni in cui il blocco finally non viene eseguito sono le seguenti:

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVM si è arrestato.
  4. Il chip Power to CPU si spegne.
  5. Il sistema operativo uccide il processo JVM.
  6. Runtime.getRuntime().exit(0);
  7. Runtime.getRuntime().halt(0);

Penso che quando JVM esce improvvisamente per qualsiasi motivo, può essere una causa che il controllo non entrerà nel blocco finally e non eseguirà mai.

Puoi renderlo parte di Daemon Thread. È ansible utilizzare il metodo setDaemon(boolean status) utilizzato per contrassegnare il thread corrente come thread daemon o thread utente e uscire dalla JVM come e quando richiesto. Questo ti consentirà di uscire dalla JVM prima che venga finally{} eseguito finally{} .

Un’altra ansible istanza di un blocco finally che non si esegue mai sarebbe dovuta a un progetto in cui il metodo è ritornato prima dell’inserimento del blocco try, come nel caso di qualche codice molto brutto che ho visto di volta in volta:

 public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException { if (checkSomeObjectState()) { return new ObjectOfSomeType(); } try { // yada yada yada... } catch (SomeHorrendousException shexc) { // wow, do something about this horrendous exception... } finally { // do some really important cleanup and state invalidation stuff... } 

So che nessuno di voi lo farebbe mai, quindi ho esitato ad aggiungere questo come ansible scenario, ma ho pensato, eh, è ​​venerdì, che diamine; )