J'ai une méthode qui est censée retourner un objet s'il est trouvé.
S'il n'est pas trouvé, dois-je:
- return null
- jeter une exception
- autre
J'ai une méthode qui est censée retourner un objet s'il est trouvé.
S'il n'est pas trouvé, dois-je:
Réponses:
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, retournez une valeur nulle.
Plus important: que faites-vous à d'autres endroits du code? La cohérence est importante.
GetPersonById(25)
lancerait si cette personne a été supprimée, mais GetPeopleByHairColor("red")
retournerait un résultat vide. Donc, je pense que les paramètres disent quelque chose sur les attentes.
Ne lancez une exception que si c'est vraiment une erreur. S'il est prévu que 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, optez pour l'exception. Si vous prévoyez le null occasionnel et que vous 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, lancez une exception.
Si null est parfois une exception, codez deux routines. Une routine lève une exception et l'autre est une routine de test booléenne qui renvoie l'objet dans un paramètre de sortie et la routine renvoie un faux si l'objet n'a pas été trouvé.
Il est difficile d'abuser d'une routine Try. Il est très facile d'oublier de vérifier la valeur null.
Donc, lorsque null est une erreur, vous écrivez simplement
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
find
et findOrFail
de Laravel Eloquent
TryFindObject
méthode? Les tuples semblent plus un paradigme paresseux pour les programmeurs qui ne veulent pas prendre le temps de définir un objet qui encapsule plusieurs valeurs. C'est essentiellement tous les tuples sont de toute façon au cœur.
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 décider de la direction à suivre. Dans la plupart des cas, seul le premier a une implémentation de l'algorithme de recherche, et les autres enveloppent simplement 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 souhaiterez peut-être utiliser une convention de dénomination comme celle-ci pour clarifier votre contrat, et cela vous aidera si vous décidez d'ajouter d'autres implémentations.
Vous ne devriez pas en abuser, mais cela peut être utile, surtout lorsque vous écrivez une classe d'assistance que vous utiliserez dans des centaines d'applications différentes avec de nombreuses conventions de gestion des erreurs.
Expected<T> findObject(String)
où Expected<T>
a les fonctions orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Ceci résume l'obtention des données de la gestion des erreurs
Utilisez le modèle d'objet nul ou lève une exception.
Person somePerson = personRepository.find("does-not-exist");
supposons que cette méthode renvoie un objet nul pour l'ID does-not-exist
. Quel serait alors le comportement correct somePerson.getAge()
? Pour l'instant, je ne suis pas encore convaincu que le modèle d'objet nul soit la bonne solution pour les recherches d'entités.
Avantages de lever une exception:
Pour plus d'explications avec des exemples, voir: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
cela dépend si votre langue et votre code favorisent: LBYL (regardez avant de sauter) ou EAFP (plus facile de demander pardon que de permission)
LBYL dit que vous devriez vérifier les valeurs (donc retournez une valeur nulle)
EAFP dit d'essayer simplement l'opération et de voir si elle échoue (lever 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 retourner un null est préférable lorsque vous utilisez des chèques.
EAFP vs LBYL en Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
( Web Archive )
Demandez-vous simplement: "est-ce un cas exceptionnel que l'objet ne soit pas retrouvé"? Si cela devrait se produire dans le cours normal de votre programme, vous ne devriez probablement pas lever une exception (car ce n'est pas un comportement exceptionnel).
Version courte: utilisez des exceptions pour gérer un comportement exceptionnel, pas pour gérer le flux normal de contrôle dans votre programme.
-Alan.
Les exceptions sont liées à la conception par contrat.
L'interface d'un objet est en fait un contrat entre deux objets, l'appelant doit respecter le contrat ou bien le récepteur peut simplement échouer avec une exception. Il existe deux contrats possibles
1) toutes les entrées de la méthode sont valides, auquel cas vous devez retourner 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 qui permet à 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é à lever une exception si rien n'est trouvé!
Dépend de ce que cela signifie que l'objet n'est pas trouvé.
Si c'est une situation normale, retournez null. C'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, puis lancez une exception, les appelants doivent décider quoi faire avec la condition d'erreur de l'objet manquant.
En fin de compte, l'un ou l'autre fonctionnerait, bien que la plupart des gens considèrent généralement comme une bonne pratique de n'utiliser les exceptions que lorsque quelque chose, enfin, exceptionnel s'est produit.
Voici quelques suggestions supplémentaires.
Si vous retournez une collection, évitez de renvoyer null, renvoyez une collection vide, ce qui facilite le traitement de l'énumération sans vérification null.
Plusieurs API .NET utilisent le modèle d'un paramètre thrownOnError qui donne à l'appelant le choix 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 courant avec BCL est le modèle TryGet où un booléen est renvoyé et la valeur est transmise via un paramètre de sortie.
Vous pouvez également prendre en compte le modèle Null Object dans certaines circonstances, qui peut être une valeur par défaut ou une version sans comportement. La clé est d'éviter les contrôles nuls dans toute la base de code. Voir ici pour plus d'informations http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Dans certaines fonctions, j'ajoute un paramètre:
..., bool verify = true)
True signifie throw, false signifie return some error return value. 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.
Renvoyer une valeur null au lieu de lever une exception et documenter clairement la possibilité d'une valeur de retour nulle dans la documentation de l'API. Si le code appelant n'honore pas l'API et ne vérifie pas le cas nul, cela entraînera très probablement une sorte d '"exception de pointeur nul" :)
En C ++, je peux penser à 3 saveurs différentes de la mise en place d'une méthode qui trouve un objet.
Option A
Object *findObject(Key &key);
Renvoie null lorsqu'un objet est introuvable. Agréable et simple. J'irais avec celui-ci. Les approches alternatives ci-dessous sont destinées aux personnes qui ne détestent pas les paramédicaux.
Option B
void findObject(Key &key, Object &found);
Passez une référence à la variable qui recevra l'objet. La méthode a levé une exception lorsqu'un objet est introuvable. Cette convention est probablement plus appropriée si l'on ne s'attend pas vraiment à ce qu'un objet ne soit pas trouvé - par conséquent, vous lancez une exception pour signifier qu'il s'agit d'un cas inattendu.
Option C
bool findObject(Key &key, Object &found);
La méthode renvoie false lorsqu'un objet est introuvable. L'avantage de cette option A est que vous pouvez vérifier le cas d'erreur en une seule étape claire:
if (!findObject(myKey, myObj)) { ...
se référant uniquement au cas où null n'est pas considéré comme un comportement exceptionnel, je suis définitivement pour la méthode try, il est clair, pas besoin de "lire le livre" ou de "regarder avant de sauter" comme cela 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()
}
...
En général, il doit retourner null. Le code appelant la méthode doit décider de lever une exception ou de tenter autre chose.
Ou retourner une option
Une option est essentiellement une classe de conteneur qui oblige le client à gérer les cas de cabine. 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 une alternative que le client spécifie.
Malheureusement, JDK est incohérent, si vous essayez d'accéder à une clé non existante dans un ensemble de ressources, vous ne recevez pas d'exception et lorsque vous demandez une valeur à la carte, vous obtenez null si elle n'existe pas. Je changerais donc la réponse du gagnant comme suit, si la valeur trouvée peut être nulle, puis déclencher une exception lorsqu'elle n'est pas trouvée, sinon retourner null. Suivez donc la règle avec une exception, si vous avez besoin de savoir pourquoi la valeur n'est pas trouvée, alors toujours lever l'exception, ou ..
Tant qu'il est censé renvoyer une référence à l'objet, le retour d'un NULL devrait être bon.
Cependant, si cela retourne tout le sang (comme en C ++ si vous faites: 'return blah;' plutôt que 'return & blah;' (ou 'blah' est un pointeur), alors vous ne pouvez pas retourner un NULL, car c'est pas de type 'objet'. Dans ce cas, lever une exception ou retourner un objet vide qui n'a pas d'indicateur de réussite est la façon dont j'aborderais le problème.
Ne pensez pas que quiconque ait mentionné les frais généraux dans la gestion des exceptions - prend des ressources supplémentaires pour charger et traiter l'exception, donc à moins qu'il ne s'agisse d'un véritable arrêt de l'application ou d'un arrêt de processus (aller de l'avant causerait plus de mal que de bien), j'opterais pour le renvoi d'un valeur que l'environnement appelant pourrait interpréter comme bon lui semble.
Je suis d'accord avec ce qui semble être le consensus ici (retourner null si "non trouvé" est un résultat normal possible, ou lever une exception si la sémantique de la situation nécessite que l'objet soit toujours trouvé).
Il existe cependant une troisième possibilité qui pourrait avoir un sens en fonction de votre situation particulière. Votre méthode peut renvoyer un objet par défaut d'une certaine sorte dans la condition "non trouvé", permettant au code appelant d'être assuré qu'il recevra toujours un objet valide sans avoir besoin de vérification nulle ou de capture d'exception.
Les exceptions devraient être exceptionnelles . Retourne null s'il est valide pour retourner un null .
Si la méthode renvoie une collection, renvoyez une collection vide (comme indiqué ci-dessus). Mais s'il vous plaît, pas Collections.EMPTY_LIST ou autre! (en cas de Java)
Si la méthode récupère un seul objet, alors vous avez quelques options.
Soyez prudent, si vous décidez de retourner un null. Si vous n'êtes pas le seul programmeur dans le projet, vous obtiendrez NullPointerExceptions (en Java ou autre dans d'autres langues) au moment de l'exécution! Ne retournez donc pas de valeurs nulles qui ne sont pas vérifiées au moment de la compilation.
null
. Voir la réponse la plus votée pour en savoir plus.
Si vous utilisez une bibliothèque ou une autre classe qui lève une exception, vous devez la relancer . 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 devez afficher 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\"");
}
}
Cela dépend vraiment si vous vous attendez à trouver l'objet ou non. Si vous suivez l'école de pensée selon laquelle les exceptions doivent être utilisées pour indiquer quelque chose, eh bien, euh, une exception s'est produite alors:
Sinon, retournez null.