web-dev-qa-db-fra.com

Une méthode de récupération doit-elle renvoyer 'null' ou émettre une exception lorsqu'elle ne peut pas produire la valeur de retour?

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

S'il n'est pas trouvé, devrais-je:

  1. retourne null
  2. jeter une exception
  3. autre
481
Robert

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.

462
Ken

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.

96
Carlton Jenke

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".

66
Matias Nino

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
50
Kevin Gale

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

  1. retourne null
  2. lancer une exception
  3. utiliser le motif d'objet nul
  4. fournit un paramètre booléen à votre méthode afin que l'appelant puisse choisir s'il souhaite que vous leviez une exception
  5. fournir un paramètre supplémentaire pour que l'appelant puisse définir une valeur qu'il récupère s'il ne trouve aucune valeur

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.

25
Lena Schimmel

Utilisez le modèle d'objet null ou émettez une exception.

18
pmlarocque

Soyez cohérent avec les API que vous utilisez.

13
dmckee

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.

11
AlanR

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 )

11
Corey Goldberg

Avantages de lancer une exception:

  1. Un flux de contrôle plus propre dans votre code d'appel. La recherche de null injecte une branche conditionnelle gérée de manière native par try/catch. La vérification de la valeur null n'indique pas ce que vous recherchez. Recherchez-vous la valeur null parce que vous recherchez une erreur que vous attendez ou recherchez-vous la valeur null afin de ne pas la transmettre plus loin dans la chaîne descendante ?
  2. Supprime l'ambiguïté de ce que "null" signifie. Nul est-il représentatif d'une erreur ou est-il nul ce qui est réellement stocké dans la valeur? Difficile à dire quand vous n’avez qu’une chose sur laquelle baser cette détermination.
  3. Amélioration de la cohérence du comportement des méthodes dans une application. Les exceptions sont généralement exposées dans les signatures de méthodes, vous permettant ainsi de mieux comprendre ce que Edge traite des méthodes dans une compte d’application et les informations auxquelles votre application peut réagir de manière prévisible.

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

10
Clifford Oravec

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é!

5
akuhn

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

4
Duncan

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.

4
swilliams

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.

4
Steve B.

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()
}
...
3
DorD

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.

3
Lev

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)) { ...
3
Ates Goral

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.

2
John Nilsson

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.

2
plinth

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.

2
Eran Galperin

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

2
Dmitriy R

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.

1
GBegen

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

1
kizzx2

Les exceptions devraient être exceptionnel. Retourne null s'il est valide de retourner une valeur nulle.

1
Andrew Lewis

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.

  1. Si la méthode doit toujours trouver le résultat et que le fait de ne pas trouver l'objet est un cas réel d'exception, vous devez alors lever une exception (en Java: s'il vous plaît une exception non cochée)
  2. (Java uniquement) Si vous pouvez tolérer que la méthode lève une exception vérifiée, lancez une exception ObjectNotFoundException spécifique au projet ou similaire. Dans ce cas, le compilateur vous dit si vous oubliez de gérer l'exception. (Ceci est ma gestion préférée des choses non trouvées en Java.)
  3. Si vous dites que c'est vraiment correct, si l'objet n'est pas trouvé et que le nom de votre méthode ressemble à findBookForAuthorOrReturnNull (..), vous pouvez alors renvoyer 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 la déréférencement du résultat sans vérification nulle. Dans le cas de Java cela peut être par exemple. FindBugs (voir DefaultAnnotation à l'adresse http://findbugs.sourceforge.net/manual/annotations.html ) ou IntelliJ-Checking.

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.

1
iuzuz

Renvoyer une valeur null, les exceptions sont exactement cela: quelque chose que votre code ne fait pas.

1
Anders

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\"");
    }

}
1
svlzx

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.

1
warren

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.

1
ScottCher

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);
} 
0
codeape

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.

0
Jeroen Dirks

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:

  • Objet trouvé; retourne l'objet
  • Objet non trouvé; lancer une exception

Sinon, retourne null.

0
Rob

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.

0
Simon Howard

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.

0

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

0
Chris Vest