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é:
System.exit(0)
est appelé; ou,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.
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 ()!
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.
Les seuls moments où finalement ne seront pas appelés sont:
si le courant est coupé
Il y a une chance d'exécution partielle quand finalement elle-même lève une exception (ou conduit à une erreur)
On pourrait être "finalement, une partie du thread démon ne peut pas être exécutée".
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; )
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{}
.