web-dev-qa-db-fra.com

Est-ce une bonne pratique connue d'utiliser un gros try-catch par méthode en java?

J'ai été interviewé récemment et l'intervieweur voulait que je fasse un test technique pour voir mes connaissances. Après l'avoir terminé, il m'a donné des commentaires sur la façon dont je l'ai fait, ce à quoi je ne m'attendais pas et j'ai apprécié, car peu d'intervieweurs le font s'ils ne veulent pas vous embaucher.

L'une des choses qu'il m'a dit qu'il voyait mal dans mon code était que j'utilisais plus d'un bloc try-catch dans chaque méthode que j'ai écrite. Cela attire mon attention car je le trouve intéressant.

Je crois pour le moment que je devrais faire des blocs try-catch où il y a un bloc de code sémantiquement distinct qui a une ou plusieurs méthodes qui peuvent lever des exceptions nécessaires pour être capturées. La seule exception à cela que j'ai suivie était que si deux méthodes lancent le même type d'exception, je ferais mieux de les placer dans différents blocs try-catch pour distinguer clairement lors du débogage où et pourquoi une exception a été levée.

Cela diffère fortement de ce que l'intervieweur voulait que je fasse. L'utilisation d'un seul bloc try-catch par méthode est-elle donc une bonne pratique connue? S'il s'agit d'une bonne pratique connue, quels en sont les avantages?

EDIT: J'apprécie grandement vos réflexions à ce sujet, c'est très bien. Bien que notez que je demande si c'est une bonne pratique connue. C'est, si la plupart des programmeurs sont d'accord sur cela, et ou c'est écrit comme une bonne pratique dans un livre

56
Adrián Pérez

Pour moi, deux blocs try-catch rendent la plupart des méthodes trop longues. Cela obscurcit l'intention si la méthode fait beaucoup de choses.

Avec deux blocs try-catch, cela fait au moins quatre choses, pour être précis

  • deux cas pour le flux principal (deux blocs d'essai)
  • deux cas pour la gestion des erreurs (blocs catch)

Je préfère faire des méthodes courtes et claires sur chaque bloc try-catch

private getHostNameFromConfigFile(String configFile, String defaultHostName) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(configFile));
        return reader.readLine();
    } catch (IOException e) {
        return defaultHostName;
    }
}
public Collection<String> readServerHostnames(File mainServerConfigFile, File  backupServerConfigFile) {
    String mainServerHostname=getHostNameFromConfigFile(mainServerConfigFile,"default- server.example.org");
    String backupServerHostName=getHostNameFromConfigFile(backupServerConfigFile,"default- server.example.ru")
    return Arrays.asList(mainServerHostname,backupServerHostName );
}

Robert C. Martin dans 'Clean Code' passe au niveau supérieur, suggérant:

si le mot-clé 'try' existe dans une fonction, ce devrait être le tout premier mot de la fonction et qu'il ne devrait rien y avoir après les blocs catch/finally.

Je voudrais certainement refactoriser la méthode avec deux blocs try/catch distincts en méthodes plus petites.

36
Bartosz Bilicki

Je dirais que si vous vous retrouvez en train d'envelopper deux blocs de code séparés avec try/catch vous devriez envisager de refactoriser ces blocs dans des méthodes distinctes. S'il s'agit d'un modèle que vous avez utilisé dans votre interview, vous avez peut-être mal compris votre intervieweur.

Il est parfaitement possible d'utiliser deux try/catch bloque si l'algorithme l'exige. J'ai souvent utilisé un nouveau try/catch dans un bloc catch pour assurer un nettoyage en toute sécurité afin qu'une instruction de couverture ne soit pas possible.

30
OldCurmudgeon

Pour répondre à votre question, lorsque nous parlons de machines virtuelles Java modernes qui appliquent en fait beaucoup d'optimisations dans le code, lorsque vous écrivez du code inefficace, la machine virtuelle Java introduira automatiquement des optimisations.

Veuillez vous référer à la réponse dans ( Java: surcharge de saisie/utilisation de blocs "try-catch"? ).

La bonne pratique n'a donc pas beaucoup d'importance.

À titre personnel, je crois qu'il ne faut rien encapsuler dans un try-catch, static, synchronized etc bloque non nécessairement.

Rendons notre code plus lisible pour ceux qui y travailleront. Si une exception est interceptée, il est préférable de mettre explicitement en évidence ce que le morceau de code la lance.

Pas de devinettes pour le lecteur, c'est pourquoi les JVM sont intelligentes, écrivez comme vous le souhaitez, améliorez-les pour les humains et JVM s'occupe de la partie optimisation.

EDIT: J'ai lu beaucoup de livres et je ne l'ai trouvé nulle part, ce qui dit qu'un gros coup d'essai vaut mieux que plusieurs petits.

De plus, beaucoup dans la communauté des développeurs pensent le contraire.

13
dharam

J'essaie d'éviter la duplication dans les blocs catch. Si toutes les exceptions d'une méthode reçoivent le même traitement dans le bloc catch, alors allez-y et rattrapez-les toutes ensemble. Si vous devez faire différentes choses avec eux, attrapez-les séparément.

Par exemple, ici, nous pouvons attraper toutes les exceptions ensemble, car tout type d'exception signifie que la méthode entière échoue:

public PasswordAuthentication readAuthenticationDetails(File authenticationFile) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(authenticationFile));
        String username = reader.readLine();
        String password = reader.readLine();
        return new PasswordAuthentication(username, password.toCharArray());
    } catch (IOException e) {
        return null;
    }
}

Alors qu'ici, nous avons un comportement de secours différent pour chaque groupe d'appels, nous interceptons donc séparément:

public Collection<String> readServerHostnames(File mainServerConfigFile, File backupServerConfigFile) {
    String mainServerHostname;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(mainServerConfigFile));
        mainServerHostname = reader.readLine();
    } catch (IOException e) {
        mainServerHostname = "default-server.example.org";
    }

    String backupServerHostname;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(backupServerConfigFile));
        backupServerHostname = reader.readLine();
    } catch (IOException e) {
        backupServerHostname = "default-server.example.ru";
    }

    return Arrays.asList(mainServerHostname, backupServerHostname);
}

(Ce code existe uniquement pour illustrer ce point sur la capture d'exceptions; je vous prie de ne pas tenir compte du fait qu'il est tout à fait horrible à d'autres égards)

9
Tom Anderson

Quant à moi, il est plus clair d'en avoir un seul try-catch bloc enveloppant tout le code "dangereux" dans une méthode. En ce qui concerne qui blâmer lorsque deux lignes lèvent la même exception, vous aurez toujours le stacktrace.

En outre, avoir plus d'un try-catch à l'intérieur d'une méthode signifie généralement avoir plus d'une return lignes (ce qui peut également rendre difficile de suivre l'exécution du code à la vue), car il est probable que si quelque chose se passe mal dans la première try-catch, cela n'aura aucun sens de continuer à exécuter le reste du code.

Vous trouverez ici quelques bonnes pratiques `` standard '', au cas où vous pourriez les trouver utiles.

http://howtodoinjava.com/2013/04/04/Java-exception-handling-best-practices/

6
ssantos

C'est une autre chose qui démarre souvent Java-flamewar ... ;-)

Fondamentalement, pour les performances, seules les exceptions sont levées. Donc, en utilisant quelques try-catch les blocs ne devraient pas du tout affecter une performance. Dans certains avis, l'écriture de code de cette manière obscurcit le code et ne rappelle même pas le "code propre", dans d'autres avis, il est préférable d'utiliser try uniquement pour les lignes qui peuvent réellement lever n'importe quelle exception.

C'est à vous de décider (ou à la convention d'équipe).

5
Eel Lee

Il est également important de considérer le contexte du code. Si vous écrivez du code avec un lourd IO alors vous devrez peut-être savoir quelles parties du code échouent. Je n'ai encore vu nulle part où essayer ... catch est destiné à vous donner une chance de récupérer d'un problème.

Donc, si vous obtenez une exception IO lors de la lecture à partir d'un fichier, vous voudrez peut-être réessayer la lecture. Même chose avec l'écriture. Mais si vous aviez un grand essai ... catch vous ne sauriez pas lequel pour réessayer.

5
Chris