J'ai une méthode qui est supposée renvoyer un objet s'il est trouvé.
S'il n'est pas trouvé, devrais-je:
Si vous vous attendez toujours à trouver une valeur, lancez l'exception si elle est manquante. L'exception signifierait qu'il y avait un problème.
Si la valeur peut être manquante ou présente et que les deux sont valides pour la logique d'application, renvoyez une valeur null.
Plus important encore: que faites-vous d'autres endroits dans le code? La cohérence est importante.
Ne jetez une exception que si c'est vraiment une erreur. Si le comportement attendu de l'objet n'existe pas, renvoyez la valeur null.
Sinon, c'est une question de préférence.
En règle générale, si la méthode doit toujours renvoyer un objet, utilisez l'exception. Si vous prévoyez le null occasionnel et souhaitez le gérer d'une certaine manière, optez pour le null.
Quoi que vous fassiez, je déconseille fortement la troisième option: renvoyer une chaîne qui dit "WTF".
Si null n'indique jamais une erreur, retournez simplement null.
Si null est toujours une erreur, alors lève une exception.
Si la valeur null est parfois une exception, codez deux routines. Une routine lève une exception et l'autre est une routine de test booléen qui renvoie l'objet dans un paramètre de sortie. La routine renvoie false si l'objet n'a pas été trouvé.
Il est difficile de mal utiliser une routine Try. C'est vraiment facile d'oublier de vérifier null.
Alors, quand null est une erreur, vous écrivez
object o = FindObject();
Lorsque le null n'est pas une erreur, vous pouvez coder quelque chose comme
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
Je voulais juste récapituler les options mentionnées précédemment, en en ajoutant de nouvelles:
Ou vous pouvez combiner ces options:
Fournissez plusieurs versions surchargées de votre getter afin que l'appelant puisse choisir la voie à suivre. Dans la plupart des cas, seul le premier dispose d'une implémentation de l'algorithme de recherche et les autres ne font qu'envelopper le premier:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Même si vous choisissez de ne fournir qu'une seule implémentation, vous pouvez utiliser une convention de dénomination comme celle-ci pour clarifier votre contrat. Cela vous aidera également si vous décidez d'ajouter d'autres implémentations.
Vous ne devriez pas en abuser, mais cela peut être utile, en particulier lors de l’écriture d’une classe d’aide que vous utiliserez dans des centaines d’applications différentes avec de nombreuses conventions de traitement des erreurs.
Utilisez le modèle d'objet null ou émettez une exception.
Soyez cohérent avec les API que vous utilisez.
Demandez-vous simplement: "est-ce un cas exceptionnel que l'objet ne soit pas trouvé"? Si cela devrait se produire dans le cours normal de votre programme, vous ne devriez probablement pas soulever d'exception (puisqu'il ne s'agit pas d'un comportement exceptionnel).
Version courte: utilisez des exceptions pour gérer un comportement exceptionnel, et non pour gérer un flux de contrôle normal dans votre programme.
-Alan.
cela dépend si votre langue et votre code favorisent: LBYL (regardez avant de sauter) ou EAFP (plus facile de demander pardon que l'autorisation)
LBYL dit que vous devriez vérifier les valeurs (retournez donc une valeur nulle)
EAFP dit d'essayer simplement l'opération et de voir si elle échoue (lève une exception)
bien que je sois d’accord avec ce qui précède, les exceptions doivent être utilisées pour des conditions exceptionnelles/d’erreur, et il est préférable de renvoyer une valeur nulle lorsque vous utilisez des chèques.
EAFP contre LBYL en Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html ( Archive Web )
Avantages de lancer une exception:
Pour plus d'explications avec des exemples, voir: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
Les exceptions sont liées à la conception par contrat.
L’interface d’un objet est en réalité un contrat entre deux objets, l’appelant doit respecter le contrat ou le destinataire peut échouer avec une exception. Il y a deux contrats possibles
1) toutes les entrées de la méthode sont valides, auquel cas vous devez renvoyer null lorsque l'objet n'est pas trouvé.
2) seule une entrée est valide, c'est-à-dire celle qui aboutit à un objet trouvé. Dans ce cas, vous DEVEZ proposer une seconde méthode permettant à l'appelant de déterminer si son entrée sera correcte. Par exemple
is_present(key)
find(key) throws Exception
SI et UNIQUEMENT SI vous fournissez les deux méthodes du 2e contrat, vous êtes autorisé à lancer une exception si rien n’a été trouvé!
Voici quelques suggestions supplémentaires.
Si vous renvoyez une collection, évitez de renvoyer null, renvoyez une collection vide qui facilite le traitement de l'énumération sans vérification préalable.
Plusieurs API .NET utilisent le modèle d'un paramètre thrownOnError qui donne à l'appelant le choix de savoir s'il s'agit vraiment d'une situation exceptionnelle ou non si l'objet n'est pas trouvé. Type.GetType en est un exemple. Un autre modèle commun avec BCL est le modèle TryGet dans lequel un booléen est renvoyé et la valeur transmise via un paramètre de sortie.
Vous pouvez également envisager le modèle Null Object dans certaines circonstances, qui peut être une version par défaut ou une version sans comportement. La clé est d'éviter les contrôles nuls dans la base de code. Voir ici pour plus d'informations http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Je préfère simplement renvoyer un null et m'appuyer sur l'appelant pour le gérer de manière appropriée. L'exception (faute d'un meilleur mot) est si je suis absolument "certain" que cette méthode retournera un objet. Dans ce cas, un échec est une exception devrait et devrait jeter.
Cela dépend de ce que cela signifie que l'objet n'est pas trouvé.
Si la situation est normale, renvoyez la valeur null. Ceci est juste quelque chose qui peut arriver de temps en temps, et les appelants doivent le vérifier.
S'il s'agit d'une erreur, émettez une exception. Les appelants doivent décider quoi faire avec la condition d'erreur d'objet manquant.
En fin de compte, l’un ou l’autre fonctionnerait, bien que la plupart des gens considèrent généralement qu’une bonne pratique consiste à n’utiliser d’Exceptions que lorsque quelque chose, eh bien, Exceptionnel s’est produit.
se référant uniquement au cas où null n'est pas considéré comme un comportement exceptionnel, je suis certainement pour la méthode try, il est clair, pas besoin de "lire le livre" ou de "regarder avant de sauter" comme il a été dit ici
donc en gros:
bool TryFindObject(RequestParam request, out ResponseParam response)
et cela signifie que le code de l'utilisateur sera également clair
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Dans certaines fonctions, j'ajoute un paramètre:
..., bool verify = true)
Vrai signifie jeter, faux signifie renvoyer une valeur de retour d'erreur. De cette façon, quiconque utilise cette fonction a les deux options. La valeur par défaut doit être vraie, pour le bénéfice de ceux qui oublient la gestion des erreurs.
Renvoie une valeur null au lieu de générer une exception et documente clairement la possibilité d'une valeur de retour null dans la documentation de l'API. Si le code d'appel n'honore pas l'API et ne vérifie pas la casse null, il en résultera probablement une sorte d '"exception de pointeur nul" de toute façon :)
En C++, je peux penser à 3 types différents de configuration d’une méthode qui trouve un objet.
Option A
Object *findObject(Key &key);
Renvoie la valeur null lorsqu'un objet est introuvable. Sympa et simple. J'irais avec celui-ci. Les approches alternatives ci-dessous sont pour les personnes qui ne détestent pas les extra-param.
Option B
void findObject(Key &key, Object &found);
Transmettez une référence à la variable qui recevra l'objet. La méthode lève une exception lorsqu'un objet est introuvable. Cette convention est probablement plus appropriée si un objet ne doit pas être trouvé - vous devez donc émettre une exception pour indiquer qu'il s'agit d'un cas inattendu.
Option C
bool findObject(Key &key, Object &found);
La méthode retourne false lorsqu'un objet est introuvable. L'avantage de cette option A est que vous pouvez rechercher le cas d'erreur en une seule étape:
if (!findObject(myKey, myObj)) { ...
Ou retourner une option
Une option est essentiellement une classe de conteneur qui oblige le client à gérer les cas de stand. Scala a ce concept, recherchez son API.
Ensuite, vous avez des méthodes comme T getOrElse (T valueIfNull) sur cet objet qui retournent soit l’objet trouvé, soit un allternatif spécifié par le client.
S'il est important que le code client connaisse la différence entre trouvé et non trouvé et qu'il s'agisse d'un comportement de routine, il est préférable de renvoyer null. Le code client peut alors décider quoi faire.
Généralement, il devrait retourner null. Le code appelant la méthode devrait décider de lancer une exception ou de tenter autre chose.
Malheureusement, JDK est incohérent. Si vous essayez d'accéder à une clé non existante dans le regroupement de ressources, vous obtenez une exception introuvable et lorsque vous demandez une valeur à la carte, vous obtenez la valeur null si elle n'existe pas. Je changerais donc la réponse du gagnant à ce qui suit, si la valeur trouvée peut être null, puis déclenche une exception si elle n’est pas trouvée, sinon je retourne null. Alors suivez la règle avec une exception, si vous avez besoin de savoir pourquoi la valeur n’est pas trouvée, toujours déclencher une exception, ou ..
Je suis d'accord avec ce qui semble être le consensus ici (retourner null si "non trouvé" est un résultat possible normal, ou jette une exception si la sémantique de la situation exige que l'objet soit toujours trouvé).
Il existe cependant une troisième possibilité qui pourrait avoir du sens en fonction de votre situation particulière. Votre méthode peut renvoyer un objet par défaut d'une sorte quelconque dans la condition "introuvable", permettant ainsi au code appelant de s'assurer qu'il recevra toujours un objet valide sans avoir besoin de la vérification de nullité ou de la capture d'exception.
Préfère retourner null -
Si l'appelant l'utilise sans vérifier, l'exception se produit quand même.
Si l'appelant ne l'utilise pas vraiment, ne lui imposez pas de bloc try
/catch
Les exceptions devraient être exceptionnel. Retourne null s'il est valide de retourner une valeur nulle.
Si la méthode retourne une collection, retournez une collection vide (comme indiqué ci-dessus). Mais s'il vous plaît pas Collections.EMPTY_LIST ou tel! (en cas de Java)
Si la méthode retrive un seul objet, vous avez quelques options.
Attention, si vous décidez de renvoyer un null. Si vous n'êtes pas le seul programmeur dans le projet, vous obtiendrez NullPointerExceptions (dans Java ou dans une autre langue) au moment de l'exécution! Donc, ne retournez pas les NULL qui ne sont pas vérifiés à la compilation.
Renvoyer une valeur null, les exceptions sont exactement cela: quelque chose que votre code ne fait pas.
Si vous utilisez une bibliothèque ou une autre classe qui lève une exception, vous devez la renvoyer . Voici un exemple. Example2.Java est comme une bibliothèque et Example.Java utilise son objet. Main.Java est un exemple pour gérer cette exception. Vous devriez montrer un message significatif et (si nécessaire) une trace de pile à l'utilisateur du côté appelant.
Main.Java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Example.Java
/**
* Example.Java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Example2.Java
/**
* Example2.Java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
Tant qu'il est supposé renvoyer un référence à l'objet, renvoyer un NULL devrait être bon.
Cependant, si le résultat est totalement sanglant (comme en C++ si vous le faites: "return blah;" plutôt que "return & blah;" (ou "blah" est un pointeur), vous ne pouvez pas retourner un NULL, car pas de type 'objet'. Dans ce cas, le fait de lever une exception ou de retourner un objet vide pour lequel aucun indicateur de réussite n'est défini est la façon dont j'aborderais le problème.
Ne pensez pas que quiconque a mentionné les frais généraux liés à la gestion des exceptions - nécessite des ressources supplémentaires pour charger et traiter l'exception. Ainsi, à moins que ce ne soit un véritable événement de destruction d'application ou de processus (l'application ferait plus de mal que de bien), j'opterais pour un renvoi valoriser l’environnement d’appel peut interpréter à sa guise.
Dans le code de la couche de données, j’utilise parfois le code suivant, permettant à l’appelant de décider si "objet non trouvé" signifie qu’une erreur est survenue.
DataType GetObject(DBConnection conn, string id, bool throwOnNotFound) {
DataType retval = ... // find object in database
if (retval != null || ! throwOnNotFound) {
return retval;
} else {
throw new NoRowsFoundException("DataType object with id {id} not found in database");
}
}
DataType GetObject(DBConnection conn, string id) {
return GetObject(conn, id, true);
}
Il ne contient pas l'objet peut se produire lors d'opérations normales et doit être traité par l'appelant, retournant NULL.
Si ne contenant pas l'objet indique un bogue par le code appelant ou par l'état interne, effectuez une assertion.
Si ne contenant pas l'objet indique un événement peu fréquent. (Comme si quelqu'un supprimait un article du magasin pendant que vous le retiriez en même temps.) Ensuite, lancez une exception.
Cela dépend vraiment de savoir si vous vous attendez à trouver l'objet ou non. Si vous suivez l’école de pensée selon laquelle des exceptions devraient être utilisées pour indiquer quelque chose, eh bien, euh, une exception est survenue alors:
Sinon, retourne null.
Cela dépend de la nature de la méthode et de son utilisation. S'il est normal que l'objet ne soit pas trouvé, renvoyez la valeur null. S'il est normal que l'objet soit toujours trouvé, émettez une exception.
En règle générale, utilisez les exceptions uniquement lorsque chose exceptionnelle. N'écrivez pas le code de telle manière que le lancement et la capture d'exceptions fassent partie de son fonctionnement normal.
Si ce n’est pas un événement exceptionnel (c’est-à-dire qu’il devrait y être dans des circonstances normales), lancez. Sinon, renvoyer une valeur "introuvable" (peut être null, mais pas obligatoirement), ou même demander à la méthode de renvoyer un booléen pour found/notfound et un paramètre de sortie pour l'objet réel.
Cela dépend de votre méthode. Si votre méthode est supposée renvoyer toujours un objet valide et qu'aucun n'est trouvé, le lancement d'une exception est le chemin à parcourir. Si la méthode consiste simplement à renvoyer un objet qui peut être ou ne pas être là (comme peut-être une image sur une personne à contacter), vous ne devriez pas générer d'erreur.
Vous pouvez également vouloir exposer une méthode renvoyant une valeur booléenne true/false si cette méthode renvoie en fait un objet. Vous n'avez donc pas à: a) vérifier la valeur null ou b) intercepter une exception
L'option "other" pourrait être de laisser la méthode find prendre un paramètre supplémentaire avec un objet par défaut qui serait renvoyé si l'objet recherché ne peut pas être trouvé.
Sinon, je retournerais simplement null sauf s'il s'agit vraiment d'un cas exceptionnel lorsque l'objet n'est pas trouvé.