Utilisation continue ou contrôlée Exceptions lors de la vérification et du traitement d'objets


3

Je suis en train de traiter, disons une liste d'objets "Document". Avant d'enregistrer le traitement du document réussi, je veux d'abord vérifier quelques éléments. Disons que le fichier faisant référence au document devrait être présent et que quelque chose devrait être présent dans le document. Juste deux simples vérifications pour l'exemple, mais pensez à 8 autres vérifications avant d'avoir traité mon document avec succès.

Qu'est-ce qui aurait votre préférence?

for (Document document : List<Document> documents) { 
    if (!fileIsPresent(document)) { 
     doSomethingWithThisResult("File is not present"); 
     continue; 
    } 
    if (!isSomethingInTheDocumentPresent(document)) { 
     doSomethingWithThisResult("Something is not in the document"); 
     continue; 
    } 
    doSomethingWithTheSucces(); 
} 

Ou

for (Document document : List<Document> documents) { 
    try { 
     fileIsPresent(document); 
     isSomethingInTheDocumentPresent(document); 
     doSomethingWithTheSucces(); 
    } catch (ProcessingException e) { 
     doSomethingWithTheExceptionalCase(e.getMessage()); 
    } 
} 

public boolean fileIsPresent(Document document) throws ProcessingException { 
    ... throw new ProcessingException("File is not present"); 
}  

public boolean isSomethingInTheDocumentPresent(Document document) throws ProcessingException { 
    ... throw new ProcessingException("Something is not in the document"); 
} 

Ce qui est plus lisible. Quel est le meilleur? Y a-t-il même une meilleure approche pour ce faire (peut-être en utilisant un modèle de conception quelconque)?

Pour autant que la lisibilité va ma préférence est actuellement la variante d'exception ...

Quelle est la vôtre?

4

Je pense qu'il serait plus lisible de refactoriser vos chèques.

for (Document document : List<Document> documents) { 
    if(checkDocument(document)) { 
     doSomethingWithTheSucces(); 
    } else { 
     doSomethingWithTheError(); 
    } 
} 

// Later: 
public boolean checkDocument(Document doc) { ... } 

Si vous n'avez pas besoin de savoir pourquoi il a échoué alors votre checkDocument() peut simplement retourner un booléen et peut-être log quel est le problème. Si votre code a besoin de savoir quel est le problème, alors quelque chose comme ceci:

for (Document document : List<Document> documents) { 
    try { 
     checkDocument(document); 
     doSomethingWithTheSucces(); 
    } catch(CheckDocumentException ex) { 
     doSomethingWithTheError(ex); 
    } 
} 

// Later: 
public void checkDocument(Document doc) throws CheckDocumentException { ... } 

Vous pouvez également checkDocument() renvoient une sorte de code de retour au lieu d'une exception, mais je pense que l'exception est meilleur pour la manutention données d'erreur complexes.

Ces deux options suppriment le besoin d'un bloc continue ou d'un grand bloc try {} et rendent généralement le code plus lisible. Il vous permet également de réutiliser la logique de vérification d'un document si vous avez besoin de le faire ailleurs plus tard.

  0

Ou peut-être même si (document.isValid()) ... Nice! Merci pour la tournure dans la réflexion à ce sujet ... 23 sept.. 082008-09-23 20:56:59

  0

Le document est valable regarde plus ou moins. Peut-être que vous pourriez simplement mettre tout ce code dans la classe Document. 24 sept.. 082008-09-24 03:40:27

  0

Je supposais (peut-être à tort) que la classe Document était scellée ou une classe intégrée, pas une classe personnalisée. En outre, écrire une méthode isValid() sur Document ne fonctionnerait que si Document sait ce qui peut être valide et ce qui ne le peut pas. En fonction de ce que fait la validation, il se peut qu'elle ne contienne pas assez d'informations. 24 sept.. 082008-09-24 13:02:11


0

Cela dépend plus de l'importance de ces deux conditions pour le flux de travail et le contexte que vous traitez. Si "l'environnement attendu" est que le fichier existe et qu'il y a du contenu dans chaque document, alors vous voudriez lancer une exception parce que c'est quelque chose qui sort de la norme et qui doit être traité dans un cas particulier. Si le "environnement attendu" est que les fichiers vont et viennent, certains ont du contenu, d'autres non, mais l'important est de parcourir la liste des fichiers transmis, puis d'avoir une instruction continue gracieuse, et potentiellement logging ou d'alerte des mauvaises données, serait préférable.


0

Ma préférence est de n'utiliser des exceptions que lorsque la situation est vraiment exceptionnelle. Par exemple, il est naturel pour nous, en tant que codeurs, de supposer qu'il existe, en fait, un fichier que nous devons traiter. Si le fichier n'est pas là, vous avez une situation exceptionnelle et peut-être irrécupérable à traiter. Toutefois, s'il manque quelque chose dans le fichier, cela peut être moins grave ou plus courant. Par exemple, si vous configurez une liste de paramètres initiaux et que l'utilisateur n'a pas spécifié l'un des paramètres attendus, vous pouvez revenir au paramètre par défaut. Ce type de comportement est considéré comme une caractéristique de notre système puisque nous exposons certains scripts de configuration et fichiers de propriétés à nos utilisateurs finaux.

Si vous avez levé une exception, en abandonnant la boucle de traitement, vous ne pouvez pas revenir en arrière. Cependant, si vous avez seulement jeté l'exception dans la boucle pour indiquer "spécification manquante, en utilisant le défaut", je ne pense pas que cela en vaille la peine.

En bref, je pense que cela dépend. Dans l'exemple spécifique que vous avez ci-dessus, je pense que je finirais par utiliser une combinaison des deux styles.


1

Utilisation continue, en particulier dans les boucles. La plupart des exceptions créent une trace de pile qui peut être un hit de performance majeur dans une boucle serrée. Vous devez remplacer fillInStackTrace pour éviter le hit. Mais stylistiquement, la règle générale est qu'une exception devrait être levée dans des situations exceptionnelles. Si vous cherchez à voir si un document existe et si vous avez certaines données à utiliser, continuez, à moins que vous n'espériez qu'ils auront tous ces données.Mais si le fichier n'existe pas ou ne correspond pas à la mise en forme est tout sauf une occurrence inattendue, n'utilisez pas d'exceptions.


1

Il ne s'agit pas de lisibilité en soi, mais de programmation sécurisée. Si vous avez détecté une erreur, vous devez vous assurer que le code client ne pourra pas l'ignorer à moins qu'il n'ait explicitement décidé de le faire (par exemple pour réessayer). En outre, les instructions 'if' sont beaucoup plus vulnérables à la corruption accidentelle de la logique due au refactoring manuel. Et comme vous pouvez le voir dans votre propre exemple, les rapports d'erreurs via des exceptions sont simplement plus lisibles.

P.S. Personnellement, je préfère utiliser des exceptions non contrôlées. Mais cela dépend du type de code que vous faites. Le mien n'a aucune raison de continuer si une exception se produit, alors je le fais juste la promotion jusqu'au code de démarrage le plus haut, où je le signale. Les exceptions non contrôlées sont moins de travail dans ce cas.