Nous avons commencé à utiliser FindBugs et à annoter nos paramètres avec @Nonnull
de manière appropriée, et cela fonctionne très bien pour signaler les bogues au début du cycle. Jusqu'à présent, nous avons continué à vérifier ces arguments pour null
en utilisant checkNotNull
de Guava, mais je préférerais vérifier null
uniquement sur les bords - des endroits où la valeur peut entrer sans avoir été vérifié pour null
, par exemple, une demande SOAP.
// service layer accessible from outside
public Person createPerson(@CheckForNull String name) {
return new Person(Preconditions.checkNotNull(name));
}
...
// internal constructor accessed only by the service layer
public Person(@Nonnull String name) {
this.name = Preconditions.checkNotNull(name); // remove this check?
}
je comprends que @Nonnull
ne bloque pas null
les valeurs elles-mêmes.
Cependant, étant donné que FindBugs indiquera n'importe où une valeur est transférée d'un champ non marqué vers un champ marqué @Nonnull
, ne pouvons-nous pas en dépendre pour attraper ces cas (ce qu'il fait) sans avoir à vérifier ces valeurs pour null
partout où elles sont transmises dans le système? Suis-je naïf de vouloir faire confiance à l'outil et d'éviter ces vérifications détaillées?
Conclusion: Bien qu'il semble sûr de supprimer le deuxième null
contrôle ci-dessous, est-ce une mauvaise pratique?
Cette question est peut-être trop similaire à Devrait-on vérifier pour null s'il ne s'attend pas à null , mais je pose spécifiquement par rapport au @Nonnull
annotation.
Si vous ne faites pas confiance à FindBug, cela peut être une option pour utiliser une assertion. De cette façon, vous évitez les problèmes mentionnés par User MSalters mais vous avez toujours un contrôle. Bien sûr, cette approche peut ne pas être applicable si une telle approche à échec rapide n'est pas possible, c'est-à-dire que vous devez intercepter toute exception.
Et pour répondre davantage à la question de savoir s'il s'agit d'une mauvaise pratique. Eh bien, c'est discutable, mais je ne pense pas. Je considère cette annotation FindBug comme une spécification légère suivant le principe de la conception par contrat.
Dans la conception par contrat, vous établissez un contrat entre une méthode et son appelant. Le contrat se compose de conditions préalables que l'appelant accepte de remplir lors de l'appel de la méthode et d'une postcondition qui à son tour est remplie par la méthode après l'exécution si sa condition préalable est remplie.
L'un des avantages de cette méthode de développement est que vous pouvez éviter un style de programmation dit défensif (dans lequel vous vérifiez explicitement toutes les valeurs de paramètres invalides, etc.). Au lieu de cela, vous pouvez compter sur le contrat et éviter les contrôles redondants pour augmenter les performances et la lisibilité.
Les contrats peuvent être utilisés pour la vérification des assertions d'exécution qui suit le principe de l'échec d'abord mentionné ci-dessus dans lequel vous voulez que votre programme échoue si un contrat est rompu, vous donnant un indice pour identifier la source d'erreur. (Une précondition échouée signifie que l'appelant a fait quelque chose de mal, une postcondition échouée indique une erreur d'implémentation de la méthode donnée)
De plus, les contrats peuvent être utilisés pour l'analyse statique, qui tente de tirer des conclusions sur le code source sans l'exécuter réellement.
L'annotation @nonnull peut être considérée comme une condition préalable utilisée pour l'analyse statique par l'outil FindBugs. Si vous préférez une approche telle que la vérification des assertions au moment de l'exécution, c'est-à-dire la première stratégie d'échec, vous devriez envisager d'utiliser les instructions d'assertion en tant que Java intégré. Ou peut-être pour s'adapter à une stratégie de spécification plus sophistiquée en utilisant un langage de spécification d'interface comportementale tel que le langage de modélisation Java JML).
JML est une extension de Java dans laquelle la spécification est incorporée dans des commentaires spéciaux Java Commentaires. Un avantage de cette approche est que vous pouvez utiliser une spécification sophistiquée, même en utilisant un approche de développement dans laquelle vous ne comptez que sur les spécifications plutôt que sur les détails d'implémentation et utilisez différents outils qui utilisent les spécifications, tels que les outils de vérification des assertions d'exécution mentionnés, la génération automatisée de tests unitaires ou de la documentation.
Si vous partagez mon point de vue selon lequel @nonnull est un contrat (léger), il serait courant de ne pas ajouter de vérifications supplémentaires car l'idée originale derrière ce principe est d'éviter la programmation défensive.
Eh bien, réfléchissez à pourquoi vous n'écrivez pas
this.name = Preconditions.checkNotNull(name); // Might be necessary
that.name = Preconditions.checkNotNull(this.name); // Who knows?
La programmation n'est pas de la magie noire. Les variables ne deviennent pas soudainement nulles. Si vous savez qu'une variable n'est pas Null et que vous savez qu'elle n'est pas modifiée, alors pas vérifiez-la.
Si vous le vérifiez, un programmeur à l'avenir (peut-être vous) passera beaucoup de temps à découvrir pourquoi ce contrôle est là. Le chèque doit être là pour une raison, après tout, alors qu'est-ce que vous négligez?