Compte tenu de ce code, puis-je être absolument sûr que le bloc finally
est toujours exécuté, peu importe ce que something()
est?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
Oui, finally
sera appelé après l'exécution des blocs de code try
ou catch
.
Les seuls moments où finally
ne seront pas appelés sont les suivants:
System.exit()
try
ou catch
kill -9 <pid>
sous UNIXfinally
est sur le point d'être exécuté par un thread de démon et que tous les autres threads non-démons se terminent avant que finally
ne soit appeléExemple de code:
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.");
}
}
Sortie:
finally trumps return.
0
En outre, bien que ce soit une mauvaise pratique, s'il existe une instruction return dans le bloc finally, elle aura priorité sur tout autre retour du bloc normal. En d'autres termes, le bloc suivant renverrait false:
try { return true; } finally { return false; }
Même chose avec les exceptions de lancement du bloc finally.
Voici les mots officiels de la spécification de langage Java.
14.20.2. Exécution d'essayer-enfin et d'essayer-attraper-finalement
Une instruction
try
avec un blocfinally
est exécutée en exécutant d'abord le bloctry
. Ensuite, il y a un choix:
- Si l'exécution du bloc
try
se termine normalement, [...]- Si l'exécution du bloc
try
se termine brusquement à cause d'unthrow
d'une valeur V, [...]- Si l'exécution du bloc
try
s'achève abruptement pour toute autre raison R, le blocfinally
est réalisé. Ensuite, il y a un choix:
- Si le bloc finally se termine normalement, l'instruction
try
se termine brusquement pour une raison R.- Si le bloc
finally
s'achève abruptement pour une raison S, l'instructiontry
s'achève abruptement pour une raison S ( et raison R est ignoré ).
La spécification de return
rend cela explicite:
JLS 14.17 The return statement
ReturnStatement: return Expression(opt) ;
Une instruction
return
sansExpression
tente de transférer le contrôle à l'appelant de la méthode ou du constructeur qui le contient.Une instruction
return
avec uneExpression
tente de transférer le contrôle à l'appelant de la méthode qui le contient; la valeur deExpression
devient la valeur de l'appel de la méthode.Les descriptions précédentes disent " tente de transférer le contrôle " plutôt que simplement " transfère le contrôle "parce que s'il existe des instructions
try
dans la méthode ou le constructeur dont les blocstry
contiennent l'instructionreturn
, les clausesfinally
de ces instructionstry
seront exécutées, dans l'ordre, du plus interne au plus externe, avant que le contrôle ne soit transféré à l'appelant de la méthode ou du constructeur. L'achèvement brutal d'une clausefinally
peut perturber le transfert du contrôle initié par une instructionreturn
.
En plus des autres réponses, il est important de souligner que 'finally' a le droit de remplacer toute valeur d'exception/renvoyée par le bloc try..catch. Par exemple, le code suivant renvoie 12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
De même, la méthode suivante ne lève pas d'exception:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
Alors que la méthode suivante le jette:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
J'ai essayé l'exemple ci-dessus avec une légère modification-
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.");
}
}
Le code ci-dessus renvoie:
l'emporte enfin sur le retour.
2
En effet, lorsque return i;
est exécuté, i
a la valeur 2. Après cela, le bloc finally
est exécuté, où 12 est affecté à i
, puis System.out
out. est exécuté.
Après avoir exécuté le bloc finally
, le bloc try
renvoie 2 au lieu de 12, car cette instruction de retour n'est pas exécutée à nouveau.
Si vous déboguez ce code dans Eclipse, vous aurez alors le sentiment qu'après l'exécution de System.out
de finally
, l'instruction return
du bloc try
est exécutée à nouveau. Mais ce n'est pas le cas. Il retourne simplement la valeur 2.
Voici une élaboration de réponse de Kevin . Il est important de savoir que l'expression à renvoyer est évaluée avant finally
, même si elle est renvoyée après.
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");
}
}
Sortie:
X
finally trumps return... sort of
0
C'est l'idée même d'un blocage final. Cela vous permet de vous assurer que vous effectuez des nettoyages qui pourraient sinon être ignorés, entre autres choses, bien sûr.
Enfin est appelé peu importe ce qui se passe dans le bloc try ( à moins que vous appeliez System.exit(int)
ou le Java La machine virtuelle est mise hors service pour une autre raison).
Une façon logique de penser à cela est:
enfin, l'exécution est toujours exécutée sauf en cas de fin anormale du programme (par exemple, en appelant System.exit (0) ..). alors, votre sysout sera imprimé
De plus, un retour à la campagne éliminera finalement toute exception. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
Le bloc finally est toujours exécuté sauf en cas de fin anormale du programme, résultant d'un crash de la machine virtuelle Java ou d'un appel à System.exit(0)
.
De plus, toute valeur renvoyée à l'intérieur du bloc finally sera prioritaire sur la valeur renvoyée avant l'exécution du bloc finally. Veillez donc à vérifier tous les points de sortie lors de l'utilisation de try finally.
Non, un cas d'exception n'est pas toujours // System.exit (0); avant que le bloc finally empêche enfin d'être exécuté.
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");
}
}
}
Finalement, c'est toujours le but, simplement parce que cela apparaît dans le code après la déclaration ne signifie pas que c'est ainsi qu'il est mis en œuvre. Le runtime Java a la responsabilité d'exécuter ce code lors de la sortie du bloc try
.
Par exemple, si vous avez ce qui suit:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
Le runtime va générer quelque chose comme ceci:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Si une exception non capturée est levée, le bloc finally
sera exécuté et l'exception continuera à se propager.
Cela est dû au fait que vous avez affecté la valeur de i à 12, mais que vous n’avez pas renvoyé la valeur de i à la fonction. Le code correct est le suivant:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Car un bloc finally sera toujours appelé à moins que vous n'appeliez System.exit()
(ou que le thread se bloque).
La réponse est simple OUI.
INPUT:
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");
}
OUTPUT:
catch
finally
Oui, il sera appelé. C'est tout l'intérêt d'avoir un mot-clé enfin. Si sauter du bloc try/catch pouvait juste ignorer le dernier bloc, c’était la même chose que de placer le System.out.println en dehors du try/catch.
Oui, enfin le bloc est toujours exécuté. La plupart des développeurs utilisent ce blocage pour fermer la connexion à la base de données, l’objet de jeu de résultats, l’objet instruction et également l’utiliser dans le Java hibernate pour annuler la transaction.
En résumé, dans la documentation officielle Java (Cliquez ici ), il est écrit que -
Si la machine virtuelle Java se ferme pendant l'exécution du code try ou catch, le bloc finally peut ne pas s'exécuter. De même, si le thread qui exécute le code try ou catch est interrompu ou tué, le bloc finally peut ne pas s'exécuter même si l'application continue dans son ensemble.
Oui, il sera. Le seul cas où cela ne se produira pas est le blocage ou la fermeture de la machine virtuelle Java
Oui, il sera. Peu importe ce qui se passe dans votre bloc try ou catch, sauf indication contraire de System.exit () ou de JVM bloquée. s'il y a une instruction de retour dans le (s) bloc (s), elle sera finalement exécutée avant cette instruction de retour.
Considérez le programme suivant:
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");
}
}
}
À partir de Java 1.8.162, le bloc de code ci-dessus donne la sortie suivante:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
cela signifie que l'utilisation de finally
pour libérer des objets est une bonne pratique à l'instar du code suivant:
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.
}
}
Ajouter à réponse de @ vibhash car aucune autre réponse n'explique ce qui se passe dans le cas d'un objet mutable comme celui ci-dessous.
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 ");
}
}
Sortie
sbupdated
finally
va s'exécuter et c'est sûr.
finally
ne sera pas exécuté dans les cas suivants:
cas 1 :
Lorsque vous exécutez System.exit()
.
cas 2:
Lorsque votre machine virtuelle/thread se bloque.
cas 3:
Lorsque votre exécution est arrêtée entre les deux manuellement.
En plus du point sur le retour dans le remplacement final d'un retour dans le bloc try, il en va de même pour une exception. Un bloc finally qui lève une exception remplacera un retour ou une exception levée depuis le bloc try.
C’est vrai dans toutes les langues ... enfin, il sera toujours exécuté avant une instruction return, quel que soit l’emplacement de ce retour dans le corps de la méthode. Si ce n'était pas le cas, le blocage final n'aurait pas beaucoup de sens.
J'ai essayé ceci, il est simple thread.
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");
}
}
}
Le fil principal sera sur l'état d'attente pour toujours, donc finalement ne sera jamais appelé,
donc la sortie de la console n'imprimera pas la chaîne: after wait()
ou finally
Convenu avec @Stephen C, l’exemple ci-dessus est l’une des 3èmes mention de cas ici :
Ajout de nouvelles possibilités de boucle infinies dans le code suivant:
// 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");
}
}
}
Cas 2: Si la machine virtuelle Java plante en premier
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);
}
}
Ref: Comment écrasez-vous une machine virtuelle?
Cas 6: Si le bloc finally est exécuté par le thread de démon et que tous les autres threads non-démons se terminent avant l'appel final.
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("-------------------------------------------------");
}
}
output: Ceci n'imprime pas "finally" ce qui implique "Enfin bloc" dans "thread démon" n'a pas été exécuté
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
Oui, car aucune instruction de contrôle peut empêcher l'exécution de finally
.
Voici un exemple de référence où tous les blocs de code seront exécutés:
| 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 |
Dans la variante ci-dessous, return x;
sera ignoré. Le résultat est toujours 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--;
}
}
Les références, bien sûr, suivent leur statut. Cet exemple retourne une référence avec 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
}
}
Si vous ne gérez pas d'exception, avant de terminer le programme, JVM exécute enfin block. Il ne sera exécuté que si l'exécution normale du programme échoue, c'est-à-dire que le programme est arrêté pour les raisons suivantes.
En provoquant une erreur fatale entraînant l'abandon du processus.
Fin du programme en raison d'une mémoire corrompue.
En appelant System.exit ()
Si le programme passe en boucle infinie.
La spécification de langage Java décrit le fonctionnement des blocs try-catch-finally et try-catch à 14.20.2
En aucun endroit, il ne spécifie que le bloc finally est toujours exécuté. Mais pour tous les cas dans lesquels les blocs try-catch-finally et try-finally sont terminés, il est précisé qu'avant l'achèvement, il doit être exécuté.
try {
CODE inside the try block
}
finally {
FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).
JLS ne garantit pas que FIN est exécuté après CODE. Le JLS garantit que si CODE et SUIVANT sont exécutés alors FIN sera toujours exécuté après CODE et avant NEXT.
Pourquoi JLS ne garantit-il pas que le bloc finally est toujours exécuté après le bloc try? Parce que c'est impossible. Il est peu probable mais possible que la machine virtuelle Java soit annulée (kill, crash, power off) juste après avoir terminé le bloc try mais avant l'exécution du bloc finally. JLS ne peut rien faire pour éviter cela.
Ainsi, tous les logiciels dont le comportement correct dépend du fait que les blocs sont toujours exécutés une fois leurs blocs d’essai terminés sont bogués.
Les retours dans le bloc try n’ont aucune incidence sur ce problème. Si l'exécution atteint le code après try-catch-finally, il est garanti que le dernier bloc aura déjà été exécuté, avec ou sans retours à l'intérieur du bloc try.
try
- catch
- finally
sont les mots clés pour utiliser le cas de traitement des exceptions.
Comme explotoire normal
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
}
Le bloc finally empêche l'exécution ...
System.exit(0);
Le bloc finally ne sera pas appelé après le retour dans quelques scénarios uniques: si System.exit () est appelé en premier ou si la machine virtuelle Java se bloque.
Laissez-moi essayer de répondre à votre question de la manière la plus simple possible.
Règle 1 : le bloc finally est toujours exécuté (bien qu'il y ait des exceptions, mais restons-y pendant un moment.)
Règle 2 : les instructions du bloc finally sont exécutées lorsque le contrôle laisse un bloc try ou catch.Le transfert du contrôle peut survenir à la suite d'une exécution normale. , de l'exécution d'une pause, continue, goto ou d'une déclaration de retour, ou d'une propogation d'une exception.
Dans le cas d'une instruction return en particulier (depuis son libellé), le contrôle doit quitter la méthode appelante, et appelle donc le bloc finally de la structure try-finally correspondante. L'instruction return est exécutée après le bloc finally.
Dans le cas où il y aurait aussi une instruction return dans le bloc finally, elle remplacera certainement celle en attente dans le bloc try, car elle efface la pile d'appels.
Vous pouvez vous référer à une meilleure explication ici: http://msdn.Microsoft.com/en-us/ .... le concept est généralement identique dans toutes les langues de haut niveau.
Oui, il est écrit ici
Si la machine virtuelle Java se ferme pendant l'exécution du code try ou catch, le bloc finally peut ne pas s'exécuter. De même, si le thread qui exécute le code try ou catch est interrompu ou tué, le bloc finally peut ne pas s'exécuter même si l'application continue dans son ensemble.
Enfin, block toujours exécuter, qu’il s’agisse ou non d’une exception. Si une exception se produisait avant le bloc try, le bloc ne sera finalement pas exécuté.
Si une exception est levée, finalement s'exécute. Si une exception n'est pas levée, finalement s'exécute. Si l'exception est interceptée, s'exécute enfin. Si l'exception n'est pas interceptée, s'exécute enfin.
Seul le temps pendant lequel elle ne s'exécute pas correspond à la fermeture de la machine virtuelle Java.
Essayez ce code, vous comprendrez le le code dans le bloc est enfin exécuté après la déclaration.
public class TestTryCatchFinally {
static int x = 0;
public static void main(String[] args){
System.out.println(f1() );
System.out.println(f2() );
}
public static int f1(){
try{
x = 1;
return x;
}finally{
x = 2;
}
}
public static int f2(){
return x;
}
}
J'étais très confus avec toutes les réponses fournies sur différents forums et j'ai finalement décidé de coder et de voir. La sortie est:
sera finalement exécuté même s'il y a un retour dans try et catch block.
try {
System.out.println("try");
return;
//int i =5/0;
//System.exit(0 ) ;
} catch (Exception e) {
System.out.println("catch");
return;
//int i =5/0;
//System.exit(0 ) ;
} finally {
System.out.println("Print me FINALLY");
}
sortie
essayer
Imprimez-moi ENFIN
System.exit(0)
dans try et attraper le bloc dans le code ci-dessus et une exception se produit avant, pour une raison quelconque.Idem avec le code suivant:
static int f() {
while (true) {
try {
return 1;
} finally {
break;
}
}
return 2;
}
f retournera 2!
Parce que la finale est toujours appelée dans tous les cas. Vous n'avez pas d'exception, il s'appelle toujours, catch exception, il s'appelle toujours
enfin, il est également possible de quitter prématurément si une exception est levée à l’intérieur d’un bloc enfin imbriqué. Le compilateur vous avertira que le bloc finally ne se termine pas normalement ou vous avertit que votre code est inaccessible. L'erreur pour le code inaccessible ne sera affichée que si le jet n'est pas derrière une instruction conditionnelle ou dans une boucle.
try{
}finally{
try{
}finally{
//if(someCondition) --> no error because of unreachable code
throw new RunTimeException();
}
int a = 5;//unreachable code
}
Oui, il sera toujours appelé, mais dans un cas, il n'appelle pas lorsque vous utilisez System.exit ()
try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
Considérez ceci dans un cours normal d'exécution (c'est-à-dire sans qu'aucune exception ne soit levée): si la méthode n'est pas 'vide', elle retourne toujours explicitement quelque chose, mais finalement, elle est toujours exécutée
Enfin on appelle toujours à la fin
lorsque vous essayez, il exécute du code; si quelque chose se produit lors de l’essai, catch interceptera cette exception et vous pouvez imprimer des messages ou émettre une erreur, puis bloquer est exécuté.
Enfin, normalement utilisé lors des nettoyages, par exemple, si vous utilisez un scanner en Java, vous devez probablement le fermer car cela pose d’autres problèmes, tels que le fait de ne pas pouvoir ouvrir certains fichiers.
enfin, block est toujours exécuté même si vous mettez une instruction return dans le bloc try. Le bloc finally sera exécuté avant l'instruction de retour.
Voici quelques conditions qui peuvent contourner un blocage final:
Dernier exemple de thread non démon:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
Sortie:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive