web-dev-qa-db-fra.com

Quelles sont les circonstances dans lesquelles un bloc finally {} NE SERA PAS exécuté?

Dans un bloc Java try{} ... catch{} ... finally{}, le code dans le finally{} est généralement considéré comme "garanti", quel que soit le déroulement de l'essai/capture. Cependant, je connais au moins deux circonstances dans lesquelles il not ne sera pas exécuté:

  • Si System.exit(0) est appelé; ou,
  • si une exception est levée jusqu'à la machine virtuelle Java et que le comportement par défaut se produit (c'est-à-dire, printStackTrace() et exit)

Existe-t-il d'autres comportements de programme qui empêcheraient le code d'un bloc finally{} de s'exécuter? Dans quelles conditions spécifiques le code sera-t-il exécuté ou non?

EDIT: Comme NullUserException l'a souligné, le second cas est en réalité faux. Je pensais que c’était parce que le texte en erreur standard était imprimé après celui en sortie standard, empêchant le texte de s’afficher sans défilement vers le haut. :) Excuses.

29
asteri

Si vous appelez System.exit() le programme se ferme immédiatement sans que finally soit appelé.

Un crash de la machine virtuelle Java, par exemple Erreur de segmentation, empêchera également l'appel final. c'est-à-dire que la machine virtuelle Java s'arrête immédiatement à ce stade et génère un rapport d'incident.

Une boucle infinie empêcherait également un appel final.

Le bloc finally est toujours appelé lorsqu'un Throwable est lancé. Même si vous appelez Thread.stop (), ce qui déclenche l'envoi d'un ThreadDeath dans le thread cible. Cela peut être attrapé (c'est une Error ) et le bloc finally sera appelé.


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<byte[]> bytes = new ArrayList<byte[]>();
            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();
}

empreintes

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

Remarque: dans chaque cas, le thread continuait de s'exécuter, même après SO, OOME, Interrupted et Thread.stop ()!

32
Peter Lawrey

Boucle infinie dans le bloc try

Corrupt RAM ? Le programme ne fonctionne plus tel quel? Je l'ai en fait débogué une fois sur une machine DOS.

9
Jeremy J Starcher

Les seuls moments où finalement ne seront pas appelés sont:

si le courant est coupé

  1. si vous appelez System.exit () 
  2. si la JVM plante en premier
  3. s'il y a une boucle infinie dans le bloc try
  4. si le courant est coupé
1
Virendra Singh

Il y a une chance d'exécution partielle quand finalement elle-même lève une exception (ou conduit à une erreur)

1
Chris

On pourrait être "finalement, une partie du thread démon ne peut pas être exécutée".

1
Tushar Paliwal

Je pense que lorsque la machine virtuelle Java quitte soudainement pour une raison quelconque, cela peut être une raison pour que le contrôle n'entre pas dans le bloc finally et ne s'exécute jamais.

Une autre instance possible d'un bloc finally jamais en cours d'exécution serait due à une conception dans laquelle la méthode est retournée avant la saisie du bloc try, comme dans le cas de très mauvais code que j'ai vu de temps en temps:

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

Je sais qu'aucun d'entre vous ne ferait cela, alors j'ai hésité à ajouter ceci comme scénario possible, mais j'ai pensé, hein, c'est vendredi, qu'est-ce qu'il se passe; )

0
idclaar

Vous pouvez en faire une partie de Daemon Thread. Vous pouvez utiliser la méthode setDaemon(boolean status) qui permet de marquer le thread actuel en tant que thread démon ou thread utilisateur et de quitter la machine virtuelle Java selon les besoins. Cela vous permettra de quitter la machine virtuelle avant l'exécution de finally{}.

0
Sambhav