Une méthode de récupération devrait-elle renvoyer 'null' ou lancer une exception lorsqu'elle ne peut pas produire la valeur de retour? [fermé]

J'ai une méthode qui est censé renvoyer un objet s'il est trouvé.

Si elle n'est pas trouvée, devrais-je:

  1. renvoie null
  2. lancer une exception
  3. autres
442
demandé sur Robert 2008-10-06 22:19:27

30 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 de l'application, renvoyez une valeur null.

Plus important: Que faites-vous d'autres endroits dans le code? La cohérence est importante.

432
répondu Ken 2008-10-06 18:21:50

Ne lance 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.

91
répondu Carlton Jenke 2008-10-06 18:21:36

En règle générale, si la méthode doit toujours retourner un objet, alors allez avec l'exception. Si vous anticipez le Null occasionnel et que vous voulez le gérer d'une certaine manière, allez avec le null.

Quoi que vous fassiez, je déconseille fortement la troisième option: renvoyer une chaîne qui dit "WTF".

62
répondu Matias Nino 2008-10-06 18:22:30

Si null n'indique jamais d'erreur, renvoyez simplement null.

Si null est toujours une erreur, lancez une exception.

Si null est parfois une exception, coder 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 D'essai. Il est très facile d'oublier de vérifier null.

Donc, quand null est un erreur que vous écrivez juste

object o = FindObject();

Lorsque la valeur 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
47
répondu Kevin Gale 2008-11-03 18:55:43

Je voulais juste récapituler les options mentionnées précédemment, en en jetant de nouvelles:

  1. renvoie null
  2. lancer une Exception
  3. utiliser le modèle d'objet null
  4. fournissez un paramètre booléen à votre méthode, afin que l'appelant puisse choisir s'il veut que vous lanciez une exception
  5. fournissez un paramètre supplémentaire, afin que l'appelant puisse définir une valeur qu'il récupère si aucune valeur n'est trouvée

, Ou vous pouvez combiner ces options:

Fournir plusieurs versions surchargées de votre getter, de sorte que l'appelant peut décider de la voie à 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 fournir une seule application, vous pouvez utiliser une convention de nommage comme ça pour clarifier votre contrat, et il vous aide si jamais vous décidez d'ajouter d'autres implémentations.

Vous ne devriez pas abuser, mais il peut être utile, en particulier lors de l'écriture d'une classe d'assistance que vous utiliserez dans des centaines d'applications différentes avec de nombreuses conventions de gestion des erreurs différentes.

22
répondu Lena Schimmel 2009-01-04 18:00:52

Utilisez le motif d'objet null ou lancez une exception.

18
répondu pmlarocque 2008-10-06 20:12:44

Soyez cohérent avec les API que vous utilisez.

12
répondu dmckee 2008-10-06 18:25:02

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 déclencher 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.

11
répondu AlanR 2008-10-06 22:16:57

Cela dépend si votre langue et votre code favorisent: Lbyl (regardez avant de sauter) ou EAFP (plus facile de demander pardon que la permission)

Lbyl dit que vous devriez vérifier les valeurs (donc renvoyer un null)
EAFP dit d'essayer l'opération et de voir si elle échoue (lancer une exception)

Bien que je suis d'accord avec ci-dessus.. les exceptions doivent être utilisées pour des conditions exceptionnelles/d'erreur, et renvoyer un null est préférable lors de l'utilisation de vérifications.


EAFP vs LBYL en Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html (Archive Web)

11
répondu Corey Goldberg 2015-10-07 10:34:49

Avantages de lancer une exception:

  1. flux de contrôle plus propre dans votre code d'appel. la vérification de null injecte une branche conditionnelle qui est gérée nativement par try / catch. La vérification de null n'indique pas ce que vous vérifiez - vérifiez-vous null parce que vous recherchez une erreur que vous attendez, ou vérifiez-vous null pour ne pas le transmettre plus loin sur downchain?
  2. supprime l'ambiguïté de ce que signifie "null". Est nulle représentant d'une erreur ou est null ce qui est réellement stocké dans la valeur? Difficile à dire quand vous n'avez qu'une chose à baser sur cette détermination.
  3. Amélioration de la cohérence entre le comportement de la méthode dans une application. les Exceptions sont généralement exposées dans les signatures de méthode, de sorte que vous êtes plus en mesure de comprendre les cas edge pour lesquels les méthodes d'une application tiennent compte et les informations auxquelles votre application peut réagir de manière prévisible.

Pour plus explication avec des exemples, voir: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

6
répondu Clifford Oravec 2011-11-17 05:35:54

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 l'autre le récepteur peut échouer avec une exception. Il y a deux contrats possibles

1) toutes les entrées la méthode est valide, auquel cas vous devez retourner null lorsque l'objet n'est pas trouvé.

2) qu'une entrée est valide, c'est à dire celle qui résulte d'un objet trouvé. Dans ce cas vous devez offrir une deuxième 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 SEULEMENT si vous fournissez les deux méthodes du 2ème Contrat, vous êtes autorisé à lancer une exception si rien n'est trouvé!

5
répondu akuhn 2008-10-06 23:37:56

Je préfère simplement renvoyer un null, et compter 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 un exceptionnel devrait et devrait jeter.

4
répondu swilliams 2008-10-06 18:20:32

Dépend de ce que cela signifie que l'objet n'est pas trouvé.

Si c'est un état normal, alors renvoyez null. C'est juste quelque chose qui pourrait arriver de temps en temps, et les appelants devraient vérifier.

Si c'est une erreur, puis lancer une exception, les appelants doivent décider quoi faire avec la condition d'erreur de l'objet manquant.

Finalement, l'un ou l'autre fonctionnerait, bien que la plupart des gens considèrent généralement comme une bonne pratique d'utiliser uniquement des Exceptions quand quelque chose, eh bien, Exceptionnel qui s'est passé.

4
répondu Steve B. 2008-10-06 18:22:42

Voici quelques suggestions.

Si vous renvoyez une collection, évitez de renvoyer null, renvoyez une collection vide qui rend l'énumération plus facile à traiter sans une vérification null en premier.

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 où a boolean est retourné et la valeur est passée via un paramètre de sortie.

Vous pouvez également considérer le modèle D'objet Null dans certaines circonstances qui peuvent être une version par défaut ou une version sans comportement. La clé est d'éviter les vérifications nulles dans toute la base de code. Voir ici pour plus d'informations http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx

4
répondu Duncan 2008-10-07 00:07:22

Dans certaines fonctions, j'ajoute un paramètre:

..., bool verify = true)

True signifie lancer, false signifie renvoyer une valeur de retour d'erreur. De cette façon, celui qui utilise cette fonction a les deux options. La valeur par défaut doit être true, pour le bénéfice de ceux qui oublient la gestion des erreurs.

3
répondu Lev 2008-10-06 20:00:19

Renvoie une valeur null au lieu de lancer une exception et documente clairement la possibilité d'une valeur de retour null dans la documentation de L'API. Si le code appelant n'honore pas L'API et vérifie le cas null, il en résultera probablement une sorte d ' "exception de pointeur null" de toute façon:)

En C++, je peux penser à 3 saveurs différentes de la mise en place d'une méthode qui trouve un objet.

L'Option A

Object *findObject(Key &key);

Renvoie null lorsqu'un objet est introuvable. Simple et sympathique. Je voudrais aller avec celui-ci. Les approches alternatives ci-dessous sont pour les personnes qui ne détestent pas out-params.

Option B

void findObject(Key &key, Object &found);

Transmet une référence à la variable qui recevra l'objet. La méthode a lancé une exception lorsqu'un objet ne peut pas être trouvé. Cette convention est probablement plus appropriée si on ne s'attend pas vraiment à ce qu'un objet ne soit pas trouvé - par conséquent, vous lancez une exception pour signifier que c'est 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 est que vous pouvez vérifier pour l'erreur dans une étape claire:

if (!findObject(myKey, myObj)) { ...
3
répondu Ates Goral 2008-10-06 22:35:47

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 "regardez avant de sauter" comme cela a été dit ici

Donc fondamentalement:

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()
}
...
3
répondu DorD 2010-12-22 16:25:45

S'il est important que le code client connaisse la différence entre found et not found et que cela soit censé être un comportement de routine, il est préférable de renvoyer null. Le code Client peut alors décider quoi faire.

2
répondu plinth 2008-10-06 18:21:21

Généralement, il devrait renvoyer null. Le code appelant la méthode doit décider de lancer une exception ou de tenter autre chose.

2
répondu Eran Galperin 2008-10-06 18:21:25

Ou renvoie une Option

Une option est essentiellement une classe de conteneur qui force 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, soit retourner l'objet trouvé, soit un allternative les spécifieces du client.

2
répondu John Nilsson 2008-10-06 19:04:45

Tant qu'il est censé renvoyer une référence à l'objet, renvoyer un NULL devrait être bon.

Cependant, s'il retourne toute la chose sanglante (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 ce n'est pas de type 'object'. Dans ce cas, lancer une exception ou renvoyer un objet vide qui n'a pas d'indicateur de succès est la façon dont j'aborderais le problème.

1
répondu warren 2008-10-06 18:23:26

Ne pensez pas que quelqu'un a mentionné la surcharge dans la gestion des exceptions - prend des ressources supplémentaires pour charger et traiter l'exception, donc à moins que ce ne soit un véritable événement de destruction d'application ou d'arrêt de processus (aller de l'avant causerait plus de mal que de bien).

1
répondu ScottCher 2008-10-06 18:29:42

Je suis d'accord avec ce qui semble être le consensus ICI (RETOURNER null si "non trouvé" est un résultat possible normal, ou lancer une exception si la sémantique de la situation exige que l'objet soit toujours trouvé).

Il y a cependant une troisième possibilité qui pourrait avoir du sens en fonction de votre situation particulière. Votre méthode pourrait renvoyer un objet par défaut dans la condition "introuvable", permettant au code appelant d'être assuré qu'il recevra toujours un objet valide sans la nécessité d'une vérification nulle ou d'une capture d'exception.

1
répondu GBegen 2008-10-06 18:36:04

Renvoie un null, les exceptions sont exactement cela: quelque chose que votre code fait qui n'est pas attendu.

1
répondu Anders 2008-10-06 19:09:04

Les Exceptions devraient être exceptionnelles . Return null s'il est valide de renvoyer un null .

1
répondu Andrew Lewis 2008-10-06 22:26:07

Préfèrent renvoyer null --

Si l'appelant l'utilise sans vérifier, l'exception se produit là de toute façon.

Si l'appelant ne l'utilise pas vraiment, ne le taxez pas try/catch bloc

1
répondu kizzx2 2011-02-23 06:02:23

Malheureusement, JDK est incohérent, si vous essayez d'accéder à une clé non existante dans le bundle de ressources, vous obtenez une exception introuvable et lorsque vous demandez une valeur à map, vous obtenez null si elle n'existe pas. Donc, je changerais la réponse du gagnant à ce qui suit, si la valeur trouvée peut être null, puis augmenter l'exception quand elle n'est pas trouvée, sinon retourner null. Donc, suivez la règle avec une exception, si vous avez besoin de savoir pourquoi la valeur n'est pas trouvée, alors levez toujours l'exception, ou..

1
répondu Dmitriy R 2011-08-03 00:32:52

Si la méthode renvoie une collection, renvoyez une collection vide (comme sayed ci-dessus). Mais s'il vous plaît pas Collections.EMPTY_LIST ou tel! (dans le cas de Java)

Si la méthode récupère un seul objet, vous avez quelques options.

  1. si la méthode doit toujours trouver le résultat et que c'est un vrai cas d'exception de ne pas trouver l'objet, alors vous devriez lancer une exception (en Java: veuillez une Exception non cochée)
  2. (Java uniquement) si vous pouvez tolérer que la méthode lance un exception cochée, lancer un ObjectNotFoundException spécifique au projet ou similaire. Dans ce cas, le compilateur vous dit si vous oubliez de gérer l'exception. (C'est mon traitement préféré des choses introuvables en Java.)
  3. Si vous dites que c'est vraiment ok, si l'objet n'est pas trouvé et que le nom de votre méthode est comme findbookforauthorreturnnull(..), alors vous pouvez retourner null. Dans ce cas, il est fortement recommandé d'utiliser une sorte de vérification statique ou de vérification du compilateur, ce qui empêche déréférencement du résultat sans vérification nulle. Dans le cas de Java, il peut être par exemple. FindBugs (voir DefaultAnnotation à http://findbugs.sourceforge.net/manual/annotations.html ) ou IntelliJ-Checking.

Soyez prudent, si vous décidez de retourner un null. Si vous n'êtes pas le seul programmeur du projet, vous obtiendrez NullPointerExceptions (en Java ou autre dans d'autres langages) au moment de l'exécution! Donc, ne renvoyez pas les valeurs NULL qui ne sont pas vérifiées au moment de la compilation.

1
répondu iuzuz 2012-08-21 21:21:31

Si vous utilisez une bibliothèque ou d'une autre classe qui lève une exception, vous devriez renvoyer il. Ici est un exemple. Exemple2.java est comme la bibliothèque et L'exemple.java utilise son objet. Principal.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.

Principal.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();
    }
}
}

Exemple.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;
        }

    }
}

Exemple2.java

 /**
 * Example2.java
 * @author Seval
 *
 */
public class Example2 {
    /**
     * Constructor of Example2
     * @throws Exception
     */
    public Example2() throws Exception{
        throw new Exception("Please set the \"obj\"");
    }

}
1
répondu svlzx 2014-10-22 12:27:19

Cela dépend vraiment si vous vous attendez à trouver l'objet, ou non. Si vous suivez l'école de pensée que les exceptions devraient être utilisées pour indiquer quelque chose, eh bien, err, exceptionnel s'est produit alors:

  • objet trouvé; objet de retour
  • objet introuvable; lancer une exception

Sinon, renvoie null.

0
répondu Rob 2008-10-06 18:21:33