Quel est le but de «enfin» dans try / catch / finally

La syntaxe changera de langue en langue, mais c’est une question générale.

Quelle est la différence entre ceci ….

try { Console.WriteLine("Executing the try statement."); throw new NullReferenceException(); } catch (NullReferenceException e) { Console.WriteLine("{0} Caught exception #1.", e); } finally { Console.WriteLine("Executing finally block."); } 

et ça….

 try { Console.WriteLine("Executing the try statement."); throw new NullReferenceException(); } catch (NullReferenceException e) { Console.WriteLine("{0} Caught exception #1.", e); } Console.WriteLine("Executing finally block."); 

Je continue de le voir utilisé, donc je suppose qu’il y a une bonne raison d’utiliser finalement, mais je ne vois pas en quoi c’est différent de simplement mettre du code après l’instruction, car il sera toujours exécuté.

Existe-t-il un scénario où finalement ne fonctionne pas?

Dans votre exemple, cela ne fait pas beaucoup de différence.

Imaginez ceci, cependant:

  try { Console.WriteLine("Executing the try statement."); throw new NullReferenceException(); } catch (SomeOtherException e) { Console.WriteLine("{0} Caught exception #1.", e); } finally { Console.WriteLine("Executing finally block."); } Console.WriteLine("Executing stuff after try/catch/finally."); 

Dans ce cas, la catch ne détectera pas l’erreur, de sorte que rien ne sera jamais atteint après le test / capture / enfin. Cependant, le bloc finally sera toujours exécuté .

 try { throw new Exception("Error!"); } catch (Exception ex) { throw new Exception(ex, "Rethrowing!"); } finally { // Will still run even through the catch kicked us out of the procedure } Console.WriteLine("Doesn't execute anymore because catch threw exception"); 

Cela dépend vraiment – certaines autres réponses ont de très bonnes raisons d’utiliser un bloc Finally . Mais je pense que la meilleure raison est que vous gérez les exceptions . Les opérations que vous effectuez dans un bloc Finally impliquent généralement le nettoyage des ressources pour garantir la continuité, indépendamment du fait qu’une exception ait été levée ou non. Pour moi, cela fait toujours partie de la gestion des exceptions , du moins d’une opération “essayer quelque chose”.

IMHO, le scope Finally souligne le fait que son code contient des éléments qui méritent une attention particulière en cas d’exception.

enfin le bloc est garanti pour être excuté. Ainsi, dans votre exemple, les résultats des deux cas sont identiques. mais si vous utilisez return ou throw votre bloc catch, vous pouvez voir quelle est la différence.

Enfin, il faut utiliser tout ce qui doit être fait pour maintenir la cohérence du système. Cela signifie généralement libérer des ressources

Enfin, il est toujours exécuté, quelle que soit l’exception levée. Il devrait être utilisé pour libérer des ressources, dans les cas suivants:

  • Finaliser une connexion
  • Fermer un gestionnaire de fichiers
  • Mémoire libre
  • Fermer une connexion à la firebase database

Laissez-moi vous donner un exemple complet. Imaginez que vous envoyez des messages via le réseau. En pseudo-code:

 // With finally | //Without finally try{ | try{ send_message() | send_message() } catch(NetworkError){ | } catch(NetworkError){ deal_with_exception() | deal_with_exception() } finally { | } finalizes_connection() | finalizes_connection() } | 

La seule différence entre les deux codes est lorsque ce qui est maintenu dans le bloc try déclenche une exception qui n’est pas NetworkError , par exemple, MethodNotFound . Dans le premier cas, la méthode finalizes_connection() sera appelée, et dans le second cas, elle ne le sera pas.

Une connexion se fait naturellement par plusieurs programmes. Alors que se passe-t-il dans le cas d’une exception MethodNotFound à l’autre programme? Dans le premier cas, votre programme finira la connexion et l’autre programme et il sera content. Dans le second cas, l’autre programme peut attendre votre réponse pour toujours. Que se passe-t-il si l’autre programme ne peut recevoir qu’une seule connexion à la fois? Vous venez juste de déranger l’autre programme.

Cela s’appliquerait également à un fichier, par exemple, que vous avez ouvert et que d’autres programmes ne pourraient pas ouvrir en lecture (sous Windows). Et pour mémoire, il n’est jamais publié et maintenant vous avez une fuite de mémoire.

finalement court pour les deux essayer et attraper. Cela garantit qu’il fonctionnera, mais il n’est pas garanti à 100% qu’il réussira [certaines erreurs empêchent l’exécution du code]

try block nécessite au moins un catch ou un finally. Après avoir exécuté tous les blocs catch, le bloc finally sera exécuté.Vous pouvez append la logique dont vous avez besoin, ce qui devrait être fait en dernier ressort.

C’est une bonne pratique à utiliser finalement pour gérer les plantages de programmes. finally sera toujours exécuté. Si la fonction se termine à l’intérieur du bloc try catch, ou si une autre erreur est renvoyée, soit dans le test, soit dans le catch, the finally sera toujours exécuté. Vous n’obtiendrez pas cette fonctionnalité sans utiliser l’instruction finally.

Je ne connais pas le langage C #, mais le but d’un bloc finally dans les langages Java-ish est de garantir que les ressources système sont abandonnées, en particulier si le garbage collection est irrégulier. C’est le même principe pour tous. Considérons le bloc

 InputStream is = new FileInputStream("foo.txt"); OutputStream os = new FileOutputStream("D:/nonexistent/directory/bar.txt"); // Throws a FileNotFoundException. 

La variable is créée avec succès et utilise les ressources système. Les processus ne peuvent utiliser qu’un nombre fixe de descripteurs de fichiers à la fois. La variable os n’est jamais créée, une exception est levée et des bulles sont émises jusqu’à l’appelant. Dans le processus, il sort du cadre et devient éligible pour le ramassage des ordures.

Cependant, il n’est jamais garanti que les collectes d’ordures se produiront, ou elles peuvent se produire ultérieurement à une date indéterminée. Ainsi, les ressources système sockets par is ne peuvent jamais être libérées. Cela peut être coûteux, ou peut bloquer le programme si cela se produit suffisamment de fois. Alors, finally blocs ont été mis en Java. D’autres langues ont des constructions similaires. En C ++, les destructeurs sont appelés de manière déterministe. Les langages LISPy sont protégés contre le unwind-protect , mais ceux-ci sont généralement regroupés dans with-foo macros with-foo .

En Java 6 et inférieur, on ferait ceci:

 try { is = new FileInputStream("foo.txt"); os = new FileOutputStream("D:/nonexistent/directory/bar.txt"); // work... } finally { if (is != null) { try { is.close(); } catch (IOException ignored) {} } if (os != null) { try { os.close(); } catch (IOException ignored) {} } } 

Vous ne pouvez pas simplement appeler is.close() car cela risquerait de se is.close() , et os ne sera jamais fermé. Vous devez vérifier null aussi. Des gens IOUtils.closeQuietly() ont IOUtils.closeQuietly() méthodes IOUtils.closeQuietly() Jakarta Commons-IO pour remplacer le bloc:

 } finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(os); } 

Mais Java 7 a introduit une meilleure solution: essayer avec des ressources. C # 4 est probablement arrivé le premier avec quelque chose de similaire, Microsoft étant plus rapide à l’absorption que Snoracle.

 try ( is = new FileInputStream("foo.txt"), os = new FileOutputStream("D:/nonexistent/directory/bar.txt") ) { // work... } 

enfin toujours toujours. est finalement comme le receveur qui ne manque de rien. Dans l’exemple que vous avez mentionné, oui, n’ajoutez aucune valeur. Mais finalement, est généralement utilisé pour éliminer / libérer des ressources.