Question

Après avoir publié cette question et la lecture celui-là Je me suis rendu compte qu'il était très important de savoir si une méthode est supposée renvoyer null, ou si cela est considéré comme une condition d'erreur et une exception doit être levée. Il existe également une bonne discussion à propos du valeur de retour & # 8216; null & # 8217; ou jeter une exception .

J'écris une méthode et je sais déjà si je souhaite renvoyer null ou une exception, quelle est la meilleure façon d'exprimer ma décision, en d'autres termes, de documenter mon contrat?

Certaines manières auxquelles je peux penser:

  • Ecrivez-le dans les spécifications / la documentation (est-ce que quelqu'un le lira?)
  • Faites-en une partie du nom de la méthode (comme je l'ai suggéré ici )
  • supposons que chaque méthode qui lève une exception ne ne renvoie pas la valeur null, et toute méthode qui «ne» lance pas pourrait renvoyer la valeur null.

Je parle principalement de Java, mais cela pourrait également s'appliquer à d'autres langues: pourquoi existe-t-il un moyen formel d'exprimer si des exceptions sont générées (les throws mots-clés), mais aucun moyen formel d'exprimer si la valeur est NULL? être retourné?

Pourquoi n'y a-t-il pas quelque chose comme ça:

public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

Résumé et conclusion

Il existe plusieurs manières d'exprimer le contrat:

  • Si votre IDE le supporte (comme IntelliJ), il est préférable d’utiliser une annotation telle que @NotNull car elle est visible par le programmeur et peut être utilisée pour la vérification automatique de la compilation. Il existe un plug-in pour Eclipse qui permet de prendre en charge ces derniers, mais cela n'a pas été le cas. travaille pour moi.
  • S'il ne s'agit pas d'une option, utilisez des types personnalisés, tels que Option<T> ou NotNull<T>, qui ajoutent de la clarté et au moins une vérification de l'exécution.
  • De toute façon, documenter le contrat dans JavaDoc ne fait jamais de mal et aide même parfois.
  • L'utilisation de noms de méthodes pour documenter la nullabilité de la valeur de retour n'a été proposée par personne d'autre que moi, et même si cela peut être très détaillé et pas toujours utile, je pense toujours que cela présente parfois des avantages, aussi.
Était-ce utile?

La solution

Une très bonne question de suivi. Je considère que null est une valeur vraiment spéciale, et si une méthode peut renvoyer @return some value ..., or null if ... elle doit clairement documenter dans le Javadoc lorsqu'elle le fera (<=>). Lors du codage, je suis sur la défensive et je suppose qu'une méthode peut renvoyer <=> à moins que je ne sois convaincue qu'elle ne le peut pas (par exemple, parce que Javadoc l'a dit.)

Les gens ont compris que c'était un problème et une solution proposée consiste à utiliser des annotations pour indiquer l'intention de manière à ce qu'elle puisse être vérifiée automatiquement. Voir JSR 305: annotations pour la détection des défauts logiciels , JSR 308: Annotations sur les types Java et Nullable How-To de JetBrain .

Votre exemple pourrait ressembler à ceci et être refusé par l'EDI, le compilateur ou d'autres outils d'analyse de code.

@NotNull
public Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

Autres conseils

Vous pouvez utiliser le Option type, qui ressemble beaucoup à une liste qui a zéro ou un élément. Un type de retour de Option<Object> indique que la méthode peut renvoyer un Object ou une valeur spéciale de type None. Ce type remplace l'utilisation de null avec de meilleures vérifications de type.

Exemple:

public Option<Integer> parseInt(String s) {
   try {
      return Option.some(Integer.parseInt(s));
   }
   catch (Exception e) {
      return Option.none();
   }
}

Si vous utilisez cette méthode de manière cohérente, vous pouvez activer les avertissements null IDE ou simplement utiliser grep pour null, ce qui ne devrait pas du tout apparaître dans votre code si vous utilisez Option.none() partout où vous utiliseriez normalement un Maybe littéral.

Iterable est livré en standard avec Scala et est appelé Option<String> en Haskell. Le lien ci-dessus renvoie à une bibliothèque appelée Java fonctionnel qui l'inclut. Cette version implémente l'interface <=> et possède des méthodes monadiques qui vous permettent de bien composer. Par exemple, pour fournir une valeur par défaut de 0 dans le cas de <=>:

int x = optionalInt.orSome(0);

Et vous pouvez remplacer ceci ...

if (myString != null && !"".equals(myString))

... avec ceci, si vous avez un <=> ...

for (String s : myOptionString)

En effet: dans notre cadre, nous avons un type de pointeur "non nul", qui peut être retourné pour indiquer que la méthode retournera toujours une valeur.

Je vois trois options:

  1. attend le support de langue pour l'exprimer (par exemple, le C #?! )
  2. utilisez Aspect Orientation pour créer vos propres extensions de langage et pour l’exprimer
  3. utilisez un type personnalisé pour l'exprimer
  4. (mais repose sur la coopération entre développeurs) utilise un schéma de nommage pour l'indiquer

Pour Java, on peut utiliser la description Javadoc d’une méthode pour documenter la signification de la valeur renvoyée, notamment si elle peut être null. Comme il a été mentionné, les annotations peuvent également apporter une assistance dans ce cas.

D’autre part, j’admets que je ne vois pas la nullité comme une chose à craindre. Il existe des situations dans lesquelles & "Personne n'est à la maison &"; est une condition significative (bien que la technique des objets nuls ait également une valeur réelle ici).

Il est certainement vrai que tenter un appel de méthode sur une valeur null provoquera une exception. Mais il en va de même pour la division par zéro. Cela ne signifie pas que nous devons mener une campagne pour éliminer les zéros! Cela signifie simplement que nous devons comprendre le contrat d’une méthode et agir correctement avec les valeurs qu’elle renvoie.

Avez-vous consulté Spec # ?

Vous pouvez écrire votre propre annotation (Java) ou votre propre attribut (C #) pour indiquer que la valeur de retour peut être null. Rien ne le vérifiera automatiquement (même si .NET 4.0 aura contrats de code pour ce genre de chose), mais il servirait au moins de documentation.

Des annotations @Nullable et @NotNull dans IntelliJ IDEA On parle également d'ajouter ces annotations (ou une fonctionnalité similaire) à Java 7. Malheureusement, je ne sais pas jusqu'où cela s'est passé ou s'il est toujours sur la bonne voie.

Vous pourriez peut-être définir une classe générique nommée & "; NotNull &"; afin que votre méthode ressemble à:

public NotNull<Object> methodWhichCannotReturnNull(int i) throws Exception
{
   // the following would lead to a run-time error thown by the
   // NotNull constructor, if it's constructed with a null value
   return new NotNull<Object>(null);
}

Il s'agit toujours d'une vérification à l'exécution (pas à la compilation), mais:

  • Cela a été jeté dans l'implémentation de la méthode (ce n'est pas une faute dans le code appelant)
  • Il s'auto-documente (l'appelant sait qu'il reçoit NotNull<T> comme type de retour)

Évitez à tout prix de vous fier aux JavaDocs. Les gens ne les lisent que si la signature ne semble pas triviale et explicite (ce qui est mauvais pour commencer), et ceux qui se donnent la peine de les lire risquent moins de se tromper avec les Nuls, car ils sont actuellement plus prudents. .

Si vous utilisez Java 5+, vous pouvez utiliser une annotation personnalisée, par exemple. @MayReturnNull

MISE À JOUR

Toute la philosophie de codage mise à part (renvoyer null, en utilisant des exceptions, des assertions, yada yada), j'espère que ce qui précède répond à votre question. Hormis les primitives ayant des valeurs par défaut, les types complexes peuvent être ou non nuls et votre code doit en tenir compte.

De manière générale, je supposerais qu'une valeur de retour nulle est contre le contrat de l'API par défaut. Il est presque toujours possible de concevoir votre code de manière à ce qu'une valeur nulle ne soit jamais renvoyée par vos API pendant & "Normal &"; flux d'exécution. (Par exemple, vérifiez foo.contains (obj) plutôt que d'appeler foo.get (obj) et d'avoir une branche distincte pour null. Ou utilisez le Modèle d'objet nul .

Si vous ne pouvez pas concevoir votre API de cette manière, je documenterais clairement quand et pourquoi une valeur null pourrait être renvoyée - au moins dans le Javadoc, et éventuellement à l'aide d'une @annotation personnalisée telle que comme l'ont suggéré plusieurs des autres réponses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top