web-dev-qa-db-fra.com

Avez-vous vraiment besoin du bloc "enfin"

Il y a 3 permutations d'essayer ... attraper ... bloquer en Java.

  1. essayer ... attraper
  2. essayez ... attrapez ... enfin
  3. essayez ... enfin

Une fois que le dernier bloc est exécuté, le contrôle passe à la ligne suivante après le dernier bloc. Si je supprime le bloc finally et déplace toutes ses déclarations sur la ligne après le bloc try ... catch, cela aurait-il le même effet que de les avoir dans le bloc finally?

62
Amit Kumar Gupta

Je pense que willcode se rapproche le plus de l'expression du point clé ici, et probablement tout le monde le dit mais n'est pas clair.

Le problème est qu’il ya vraiment quelque chose qui cloche dans ce que vous demandez: "Si j’écris toutes les instructions après un blocage au lieu de les écrire dans un bloc final, il y aurait-il un problème?" 

Si vous écrivez toutes les déclarations après le bloc catch, vous sous-entendez que 

1) Vous attraperez toujours l'exception.

2) Vous passerez toujours aux instructions suivantes après avoir intercepté l'exception.

Cela implique que vous continuerez toujours l'exécution "normalement" après une exception, ce que vous voulez en fait faire jamais.

Les exceptions devraient être justes - exceptionnelles. Si vous pouvez réellement gérer une exception, il est toujours préférable d'écrire votre code pour prendre en compte ces conditions en premier et ne pas conduire à une exception du tout. Si vous suivez ce modèle, les exceptions sont vraiment exceptionnelles - des conditions que vous ne pouvez pas anticiper ou tout au plus ne pas corriger. Vraiment pas anticiper est ce que vous devriez travailler. Cela signifie généralement que vous ne pouvez pas gérer les vraies exceptions, ce qui signifie également que vous ne devez pas simplement continuer l'exécution, mais que vous quittez souvent l'application à la place. _

Normalement, vous laissez une erreur se propager dans la pile d’appels. Certains disent que cela se fait au hasard, si quelqu'un de haut dans la chaîne est capable de s'en occuper. Je dirais que cela ne se produit pratiquement jamais, il y a deux véritables objectifs. L’un peut être quelque chose que l’utilisateur peut réparer, s’il en existe un. Donc, vous propagez l'erreur en arrière jusqu'à ce que vous puissiez la signaler à l'utilisateur. Ou deux, un utilisateur ne peut pas le réparer mais vous voulez obtenir la pile d'appels complète pour le débogage. Ensuite, vous attrapez au sommet pour échouer gracieusement.

Le bloc finally devrait maintenant avoir plus de sens pour vous. Comme tout le monde le dit, ça coule toujours. L'utilisation la plus claire d'un enfin est vraiment dans un essai ... enfin bloquer. Ce que vous dites maintenant, c’est que si le code fonctionne correctement, très bien. Nous avons encore besoin de faire un peu de ménage et finalement, il exécute toujours, puis nous passons à autre chose. Mais si une exception se produit, nous avons vraiment besoin de ce blocage final, car nous avons peut-être encore besoin de nettoyer, mais nous ne la détectons plus ici, nous ne pourrons plus continuer. Enfin, le blocage est essentiel pour garantir le nettoyage.

L'idée d'une exception interrompant toujours l'exécution peut être difficile à appréhender tant qu'elle n'a pas une certaine expérience, mais c'est en fait le moyen de toujours faire les choses. Si une erreur se produisait, soit elle était si mineure que vous auriez dû vous en rendre compte au début, ou bien il y a de plus en plus d'erreurs en attente de se produire.

Erreurs de "déglutition" - les détecter et passer à autre chose est la pire chose à faire, car votre programme devient imprévisible et vous ne pouvez ni trouver, ni corriger les bogues.

Un code bien écrit contiendra autant de blocs try ..., enfin, nécessaires pour vous assurer que les ressources sont toujours libérées, quel que soit le résultat. Mais le code bien écrit ne contient généralement qu'un petit nombre de blocs try ... catch qui existent principalement pour permettre à une application d'échouer aussi gentiment que possible ou de la reporter à l'utilisateur, ce qui signifie au moins toujours lui transmettre un message, etc. Mais en général, vous ne détectez pas une erreur et continuez.

45
Sisyphus

Je sais que la question est très ancienne, mais j’ai rencontré aujourd’hui et j’ai été dérouté par les réponses fournies. Je veux dire, ils sont tous corrects mais répondent tous sur un plan théorique ou même philosophique quand il y a une réponse pratique très simple à cette question.

Si vous spécifiez return, break, continue ou tout autre mot clé Java modifiant l'exécution séquentielle du code dans le bloc catch (ou même try block), les instructions contenues dans le bloc finally seront toujours exécutées.

Par exemple:

public void myFunc() {

    double p = 1.0D;
    String str = "bla";
    try{
        p = Double.valueOf(str);
    }
    catch(Exception ex){
        System.out.println("Exception Happened");
        return;  //return statement here!!!
    }finally{
        System.out.println("Finally");
    }
    System.out.println("After finally");
}

une fois exécuté, ce code sera imprimé:

Exception Happened 
Finally

C’est la raison la plus importante de l’existence d’un blocage final. La plupart des réponses impliquent ou font allusion à cela, mais aucune d’elles ne met l’accent sur elle. Parce que c’est un peu une question pour les débutants, je pense qu’une réponse aussi simple est très importante.

49

Le fait saillant est qu'un bloc finally est garanti pour être exécuté même si une exception est levée et n'est pas interceptée. Vous utilisez ensuite le bloc finally, comme une occasion unique, pour effectuer le nettoyage nécessaire, tel que la fermeture de flux. Le code après le bloc finally pourrait ne jamais être atteint.

Depuis le Java tutorial

Le bloc finally est toujours exécuté quand le bloc try se termine. Cela garantit que le bloc finally est exécuté même si une exception inattendue se produit. Mais enfin est utile pour plus que juste gestion des exceptions - il permet à la programmeur pour éviter le nettoyage code contourné accidentellement par un revenir, continuer ou faire une pause. En mettant Le code de nettoyage dans un bloc finally est toujours une bonne pratique, même quand non des exceptions sont prévues.

39

Si je comprends la question, vous demandez quelle est la différence entre:

try {
    Foo f = new Foo();
    f.bar();
}
finally
{
    Foo.baz();
}

Et:

// This doesn't actually compile because a try block needs a catch and/or finally block
try {
    Foo f = new Foo();
    f.bar();
}
Foo.baz();

Ou plus probablement:

Foo f = new Foo();
f.bar();
Foo.baz();

La différence est que si new Foo() ou f.bar() lève une exception, le bloc finally sera exécuté dans le premier cas, mais Foo.baz() ne sera pas exécuté dans les deux derniers cas: le contrôle ignorera alors Foo.baz() pendant que la machine virtuelle recherche un gestionnaire d'exception.


MODIFIER

En réponse à votre commentaire, qu'en est-il:

Foo f = new Foo();
try {
    f.bar();
}
catch (Exception ex)
{
    // ...
}

f.baz();

Vous avez raison de dire que, si le bloc catch ne réexécute pas l’exception ou ne renvoie pas la méthode qui indique qu’un échec est survenu, alors f.baz() est appelé, qu’il y ait eu ou non une exception. Même dans ce cas, toutefois, le bloc finally sert de documentation indiquant que f.baz() est utilisé pour le nettoyage.

Plus important encore, le fait qu'une exception soit générée est généralement important, il est donc très difficile d'écrire du code qui continue à faire ce qu'il a fait sans savoir qu'une exception a été générée. Il arrive que des exceptions indiquent des choses stupides que vous pouvez ignorer et dans ce cas, vous devez les avaler. Le plus souvent, toutefois, vous souhaiterez signaler un échec, soit en renvoyant l'exception (ou en lançant une exception différente), soit en renvoyant la méthode avec un code d'erreur.

Par exemple, si f.bar() est supposé convertir une String en Double et que, en cas d'échec, il lance un NumberFormatException , le code situé après le bloc try doit probablement savoir que String n'a pas été réellement converti en Double. Et donc, en général, vous ne voudrez plus continuer après le bloc catch. Au lieu de cela, vous voudrez signaler l'échec. C'est ce que l'on appelle "abandon sur échec" (par opposition à "reprise sur échec", qui devrait probablement s'appeler "confusion après échec avec les doigts croisés").

Sauf que, dans des cas particuliers, vous pourrez vous débrouiller. Par exemple, le bloc catch peut définir la Double pertinente sur Double.NaN , conçue spécifiquement pour propager correctement les erreurs dans les expressions mathématiques. Même dans ce cas, le bloc finally sert de documentation selon laquelle f.baz() est impliqué dans un type de nettoyage.

10
Max Lybbert

Le bloc finally contient des lignes de code qui doivent être exécutées, qu'une exception ait été interceptée ou non. Même si vous décidez d'arrêter l'exécution du code avec cette méthode. Donc, le code après le t-c-f peut ne pas être exécuté, mais le code final est "garanti" (garanti dans le sens d'une erreur non résolutive, cassant immédiatement l'erreur non manipulable).

3
Sascha

Oui, il y aurait quelque chose de très grave.

Et c’est-à-dire que votre code ne fonctionnera que s’il ya une erreur.

Les instructions dans finally sont toujours exécutées, quelle que soit l’exception levée. C'est le but.

2
Noon Silk

enfin bloc spécialement utilisé au moment de la prévention des exceptions. Si une erreur d'exécution se produit, le programme peut conduire à une fin. Donc, à ce moment, il va appeler finalement bloquer avant d'aller terminer le programme. Généralement, "finalement" contient les instructions de fermeture de la connexion, les opérations de sauvegarde et de saisie de fichier, les opérations de fermeture de sortie. 

2
janasainik

Si votre code ne lève jamais d'exception ou si vous utilisez toutes les exceptions qui seront correctes. Ce n'est pas ce qui se passe toujours.

1
fastcodejava

Il y a deux mois, j'ai écrit un article pour la raison derrière "enfin" dans un essai/capture.

Conscient du fait qu'un lien empêche la modification de la manière d'un wiki, ici. 

Il s’agit d’une publication autonome dont la simple copie ne fonctionnerait pas car vous auriez oublié le commentaire suivant qui ajoute également de la valeur.

0
qnoid