Question

Compte tenu de ce code, puis-je être absolument sûr que le bloc finally est toujours exécuté, quel que soit quelque chose () ?

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

La solution

Oui, enfin sera appelé après l'exécution des blocs de code try ou catch .

Les seules fois où finalement ne sera pas appelé sont les suivantes:

  1. Si vous appelez System.exit ()
  2. Si la machine virtuelle Java tombe en panne en premier
  3. Si la machine virtuelle Java atteint une boucle infinie (ou une autre instruction non interruptible, sans fin) dans le bloc try ou catch
  4. Si le système d'exploitation met fin de force au processus JVM; Par exemple, kill -9 < pid > sous UNIX
  5. Si le système hôte meurt; par exemple, panne de courant, erreur matérielle, panique du système d'exploitation, etc.
  6. Si le bloc finally va être exécuté par un thread de démon et que tous les autres threads non-démons se terminent avant que finally soit appelé

Autres conseils

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

De plus, 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 générées depuis le bloc finally.

Voici les mots officiels de la spécification du langage Java.

14.20.2. Exécution de try-finally et try-catch-finally

  

Une instruction try avec un bloc finally est exécutée en exécutant d'abord le bloc try . 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 abruptement à cause d'un jette d'une valeur V , [...]
  •   
  • Si l'exécution du bloc try s'achève abruptement pour toute autre raison R , le bloc finally est exécuté. Ensuite, il y a un choix:      
        
    • Si le bloc finally se termine normalement, l'instruction try se termine brusquement pour la raison R .
    •   
    • Si le bloc finally s'achève abruptement pour la raison S , l'instruction try se termine abruptement pour la raison S ( et la raison pour laquelle R est jeté ).
    •   
  •   

La spécification de return rend cette explicite explicite:

JLS 14.17 La déclaration de retour

ReturnStatement:
     return Expression(opt) ;
     

Une instruction return sans Expression tente de transférer le contrôle à l'appelant de la méthode ou du constructeur qui le contient.

     

Une instruction return avec une Expression tente de transférer le contrôle à l'appelant de la méthode qui le contient; la valeur de Expression devient la valeur de l'appel de la méthode.

     

Les descriptions précédentes indiquent que " tente de transférer le contrôle ". au lieu de simplement " transférer le contrôle " parce que s'il existe des instructions try dans la méthode ou le constructeur dont les blocs try contiennent l'instruction return , alors tout code finally de ces instructions try 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 clause finally peut perturber le transfert du contrôle initié par une instruction return .

Outre les 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 génère 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

Cela est dû au fait que lorsque renvoyer i; est exécuté, i a la valeur 2. Après cela, le bloc finally est exécuté, où 12 est attribué. i , puis System.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 l’impression qu’après l’exécution de System.out de finally , bloquer le return . L’instruction du bloc try est exécutée à nouveau. Mais ce n'est pas le cas. Il renvoie simplement la valeur 2.

Voici une élaboration de la 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, il est appelé quoi que se passe dans le bloc try ( sauf si vous appelez System.exit (int) ou la machine virtuelle Java pour une autre raison).

Une façon logique de penser à cela est:

  1. Le code placé dans un bloc finally doit être exécuté quoi que se produise dans le bloc try
  2. Ainsi, si le code du bloc try tente de renvoyer une valeur ou une exception, l'élément est placé "sur l'étagère" jusqu'à ce que le dernier bloc puisse s'exécuter
  3. Etant donné que le code du bloc finally a (par définition) une priorité élevée, il peut être renvoyé ou projeté à sa guise. Dans ce cas, tout ce qui reste "sur l'étagère" est jeté.
  4. La seule exception à cette règle est que la VM s'arrête complètement pendant le bloc try, par exemple. par 'System.exit'

De plus, un retour en interne supprimera définitivement toute exception. http://jamesjava.blogspot.com/2006/03 /dont-return-in-finally-clause.html

Enfin,

est toujours exécuté sauf en cas de fin anormale du programme (par exemple, en appelant System.exit (0) ..). alors, votre sysout sera imprimé

Le bloc finally est toujours exécuté sauf en cas d'arrêt anormal du programme, résultant d'un blocage de la machine virtuelle Java ou d'un appel à System.exit (0) .

De plus, toute valeur renvoyée à l'intérieur du bloc finally remplacera 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, il n'y a pas toujours un cas d'exception // 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, juste parce que cela apparaît dans le code après le retour ne veut pas dire que c'est comme ça que ça est implémenté. Le runtime Java a la responsabilité d’exécuter ce code lors de la sortie du bloc try .

Par exemple, si vous possédez les éléments suivants:

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

Le moteur d’exécution génèrera 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;
    }
}

Parce qu'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 .

ENTREE:

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

SORTIE:

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 simplement ignorer le dernier bloc, c’était la même chose que de placer System.out.println en dehors du try / catch.

De manière concise, dans la documentation Java officielle (cliquez sur 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 fil en cours d'exécution   si le code try ou catch est interrompu ou tué, le blocage   pas exécuter même si l'application dans son ensemble continue.

Oui, enfin le bloc est toujours exécuté. La plupart des développeurs utilisent pour ce faire la fermeture de la connexion à la base de données, l’objet de jeu de résultats, l’objet instruction et également l’utilisation dans le java hibernate pour annuler la transaction.

Oui, ça ira. 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 ou les blocs, elle sera finalement exécutée avant cette instruction de retour.

Oui ça va. Le seul cas où cela ne se produira pas est que JVM quitte ou se bloque

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.
    }
}

C’est vrai dans toutes les langues ... enfin, il s’exécutera toujours 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.

enfin va s'exécuter et c'est sûr.

finalement ne sera pas exécuté dans les cas suivants:

cas 1:

Lorsque vous exécutez System.exit () .

cas 2:

Lorsque votre JVM / Thread tombe en panne.

cas 3:

Lorsque votre exécution est arrêtée manuellement entre.

Si vous ne gérez pas d'exception, avant de mettre fin au programme, JVM exécute enfin block. Il ne sera exécuté que si l'exécution normale du programme échoue. Cela signifie que le programme doit être terminé pour les raisons suivantes.

  1. En provoquant une erreur fatale entraînant l’abandon du processus.

  2. Fin du programme en raison d'une mémoire corrompue.

  3. En appelant System.exit ()

  4. Si le programme passe en boucle à l'infini.

Oui, car aucune instruction de contrôle ne peut empêcher l'exécution de finally .

Voici un exemple de référence dans lequel 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 renvoie 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
    }
}

try - catch - finally sont les mots clés permettant d'utiliser le cas de traitement des exceptions.
En tant qu’explication normale

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 ...

  • Lorsque vous avez appelé System.exit (0);
  • Si la machine virtuelle Java est fermée.
  • Erreurs dans la machine virtuelle

L'ajout à La 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 ");
    }
}

affichera

sbupdated 

J'ai essayé ça, Il s’agit d’un seul 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 en attente pour toujours, donc finalement ne sera jamais appelé,

afin que la sortie de la console n'imprime pas la chaîne: après wait () ou enfin

Convenu avec @Stephen C, l’exemple ci-dessus est l’un des cas mentionnés en troisième 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 se bloque 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);
    }
}

Réf.: Comment écraser une machine virtuelle Java?

Cas 6: Si un bloc doit finalement être exécuté par un thread démon et que tous les autres threads non-démons se terminent avant que l'appel ne soit finalement lancé.

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

sortie: ceci n'imprime pas "enfin". ce qui implique "enfin bloc" dans " fil de démon " n'a pas 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top