Je cherche à rendre mon code plus lisible et à utiliser des outils comme l'inspection de code IDE et / ou l'analyse de code statique (FindBugs et Sonar) pour éviter les exceptions NullPointerExceptions. De nombreux outils semblent incompatibles avec l' annotation @NotNull
/ @NonNull
/ de l'autre @Nonnull
et les énumérer tous dans mon code serait terrible à lire. Avez-vous des suggestions dont la meilleure? Voici la liste des annotations équivalentes que j'ai trouvées:
javax.validation.constraints.NotNull
Créé pour la validation d'exécution, pas pour l'analyse statique.
Documentationedu.umd.cs.findbugs.annotations.NonNull
Utilisé par Findbugs analyse statique et donc Sonar (maintenant sonarqube )
documentationjavax.annotation.Nonnull
Cela peut également fonctionner avec Findbugs, mais JSR-305 est inactif. (Voir aussi: Quel est le statut de JSR 305? ) Sourceorg.jetbrains.annotations.NotNull
Utilisé par IntelliJ IDEA IDE pour l'analyse statique.
Documentationlombok.NonNull
Utilisé pour contrôler la génération de code dans Project Lombok .
Annotation d'espace réservé car il n'y a pas de norme.
source , documentationandroid.support.annotation.NonNull
Annotation de marqueur disponible dans Android, fournie par la documentation du package support-annotations
org.eclipse.jdt.annotation.NonNull
Utilisé par Eclipse pour la documentation d' analyse de code statique
com.sun.istack.internal.NotNull
. OMG ...Réponses:
Depuis JSR 305 (dont l'objectif était de normaliser
@NonNull
et@Nullable
) est en sommeil depuis plusieurs années, je crains qu'il n'y ait pas de bonne réponse. Tout ce que nous pouvons faire est de trouver une solution pragmatique et la mienne est la suivante:Syntaxe
D'un point de vue purement stylistique, je voudrais éviter toute référence à l'IDE, au framework ou à toute boîte à outils à l'exception de Java lui-même.
Cela exclut:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Ce qui nous laisse avec
javax.validation.constraints
oujavax.annotation
. Le premier est livré avec JEE. Si c'est mieux que celajavax.annotation
, qui pourrait éventuellement arriver avec JSE ou jamais du tout, c'est un sujet de débat. Personnellement, je préfèrejavax.annotation
parce que je n'aimerais pas la dépendance JEE.Cela nous laisse avec
javax.annotation
qui est aussi le plus court.
Il n'y a qu'une syntaxe qui serait même mieux:
java.annotation.Nullable
. Comme d'autres packages sont passés dejavax
àjava
dans le passé, l'annotation javax serait un pas dans la bonne direction.la mise en oeuvre
J'espérais qu'ils ont tous fondamentalement la même implémentation triviale, mais une analyse détaillée a montré que ce n'est pas vrai.
D'abord pour les similitudes:
Les
@NonNull
annotations ont toutes la ligneà l'exception de
org.jetbrains.annotations
qui l'appelle@NotNull
et a une implémentation trivialejavax.annotation
qui a une mise en œuvre plus longuejavax.validation.constraints
qui l'appelle aussi@NotNull
et a une implémentationLes
@Nullable
annotations ont toutes la lignesauf (encore) le
org.jetbrains.annotations
avec leur implémentation triviale.Pour les différences:
Un frappant est que
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
tous ont des annotations d'exécution (
@Retention(RUNTIME)
), tandis queandroid.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
ne sont que du temps de compilation (
@Retention(CLASS)
).Comme décrit dans cette réponse SO, l'impact des annotations d'exécution est plus petit qu'on ne le pense, mais elles ont l'avantage d'activer des outils pour effectuer des vérifications d'exécution en plus de celles de la compilation.
Une autre différence importante est l' endroit où dans le code les annotations peuvent être utilisées. Il existe deux approches différentes. Certains packages utilisent des contextes de style JLS 9.6.4.1. Le tableau suivant donne un aperçu:
org.eclipse.jdt.annotation
,javax.annotation
Etorg.checkerframework.checker.nullness.qual
utiliser les contextes définis dans JLS 4,11, ce qui est à mon avis la bonne façon de le faire.Cela nous laisse avec
javax.annotation
org.checkerframework.checker.nullness.qual
dans ce tour.
Code
Pour vous aider à comparer vous-même d'autres détails, j'énumère ci-dessous le code de chaque annotation. Pour faciliter la comparaison, j'ai supprimé les commentaires, les importations et l'
@Documented
annotation. (ils avaient tous@Documented
sauf les classes du package Android). J'ai réorganisé les lignes et les@Target
champs et normalisé les qualifications.Pour être complet, voici les
@Nullable
implémentations:Les deux packages suivants n'en ont pas
@Nullable
, je les énumère donc séparément; Lombok a un assez ennuyeux@NonNull
. Dansjavax.validation.constraints
le@NonNull
est en fait un@NotNull
et il a une implémentation assez longue.Soutien
D'après mon expérience,
javax.annotation
est au moins pris en charge par Eclipse et le Checker Framework hors de la boîte.Sommaire
Mon annotation idéale serait la
java.annotation
syntaxe avec l'implémentation de Checker Framework.Si vous n'avez pas l'intention d'utiliser le Checker Framework, le
javax.annotation
( JSR-305 ) reste votre meilleur pari pour le moment.Si vous êtes prêt à acheter dans le Checker Framework, utilisez simplement leur
org.checkerframework.checker.nullness.qual
.Sources
android.support.annotation
deandroid-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
defindbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
deorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
dejetbrains-annotations-13.0.jar
javax.annotation
degwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
dechecker-framework-2.1.9.zip
lombok
delombok
commitf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
devalidation-api-1.0.0.GA-sources.jar
la source
javax.annotation
est qu'il est a) basé sur un JSR mort, b) difficile de trouver un artefact qui fournit simplement les annotations et est maintenu. Celui de findbugs n'est pas: search.maven.org/…javax.annotation
est qu'il cause des problèmes avec Java 9 car d'autres modules fournissent également des classes dans ce package (jax-ws).javax.annotation.NonNull
, n'a jamais été achevé car son avance en matière de spécifications a disparu. Cela n'avait rien à voir avec une décision d'Oracle.J'aime beaucoup le Checker Framework , qui est une implémentation d'annotations de type ( JSR-308 ) qui est utilisée pour implémenter des vérificateurs de défauts comme un vérificateur de nullité. Je n'ai pas vraiment essayé d'autres pour proposer une comparaison, mais j'ai été satisfait de cette implémentation.
Je ne suis pas affilié au groupe qui propose le logiciel, mais je suis fan.
Quatre choses que j'aime dans ce système:
Il a un vérificateur de défauts pour la nullité (@Nullable), mais a également ceux pour l' immuabilité et l' internement (et autres). J'utilise le premier (nullité) et j'essaie de me lancer dans le second (immuabilité / IGJ). J'essaie le troisième, mais je ne suis pas encore sûr de l'utiliser à long terme. Je ne suis pas encore convaincu de l'utilité générale des autres vérificateurs, mais il est bon de savoir que le cadre lui-même est un système pour implémenter une variété d'annotations et de vérificateurs supplémentaires.
Le paramètre par défaut pour la vérification de la nullité fonctionne bien: Non nul sauf les locaux (NNEL). Fondamentalement, cela signifie que par défaut, le vérificateur traite tout (variables d'instance, paramètres de méthode, types génériques, etc.) à l'exception des variables locales comme si elles avaient un type @NonNull par défaut. Selon la documentation:
Vous pouvez définir une valeur par défaut différente pour une classe ou pour une méthode si NNEL ne fonctionne pas pour vous.
Ce framework vous permet d'utiliser avec sans créer de dépendance sur le framework en enfermant vos annotations dans un commentaire: eg
/*@Nullable*/
. C'est bien parce que vous pouvez annoter et vérifier une bibliothèque ou un code partagé, mais toujours pouvoir utiliser cette bibliothèque / codée partagée dans un autre projet qui n'utilise pas le framework. C'est une fonctionnalité intéressante. Je me suis habitué à l'utiliser, même si j'ai tendance à activer le Checker Framework sur tous mes projets maintenant.Le cadre a un moyen d' annoter les API que vous utilisez qui ne sont pas déjà annotées pour la nullité en utilisant des fichiers de raccord.
la source
J'utilise celui d'IntelliJ, car je suis principalement préoccupé par le signalement d'IntelliJ qui pourrait produire un NPE. Je suis d'accord que c'est frustrant de ne pas avoir d'annotation standard dans le JDK. Il est question de l'ajouter, il pourrait en faire Java 7. Dans ce cas, il y en aura un de plus à choisir!
la source
javax.annotation.Nonnull
est plus largement accepté, n'est-ce pas?Selon la liste des fonctionnalités de Java 7, les annotations de type JSR-308 sont reportées à Java 8. Les annotations JSR-305 ne sont même pas mentionnées.
Il y a un peu d'informations sur l'état de JSR-305 dans une annexe du dernier projet de JSR-308. Cela inclut l'observation que les annotations JSR-305 semblent être abandonnées. La page JSR-305 le montre également comme "inactif".
En attendant, la réponse pragmatique est d'utiliser les types d'annotation pris en charge par les outils les plus utilisés ... et d'être prêt à les changer si la situation change.
En fait, JSR-308 ne définit aucun type / classe d'annotation, et il semble qu'ils pensent qu'il est hors de portée. (Et ils ont raison, étant donné l'existence de JSR-305).
Cependant, si JSR-308 a vraiment l'air de devenir Java 8, cela ne me surprendrait pas si l'intérêt pour JSR-305 revenait. AFAIK, l'équipe JSR-305 n'a pas officiellement abandonné son travail. Ils sont juste silencieux depuis plus de 2 ans.
Il est intéressant de noter que Bill Pugh (le responsable technique de JSR-305) est l'un des gars derrière FindBugs.
la source
Pour les projets Android, vous devez utiliser
android.support.annotation.NonNull
etandroid.support.annotation.Nullable
. Ces annotations utiles et spécifiques à Android sont disponibles dans la bibliothèque de support .Depuis http://tools.android.com/tech-docs/support-annotations :
la source
javax.annotation.*
annotations égalementSi quelqu'un cherche simplement les classes IntelliJ: vous pouvez les obtenir à partir du référentiel maven avec
la source
JSR305 et FindBugs sont créés par la même personne. Les deux sont mal entretenus mais sont aussi standard que possible et sont pris en charge par tous les principaux IDE. La bonne nouvelle, c'est qu'ils fonctionnent bien tels quels.
Voici comment appliquer @Nonnull à toutes les classes, méthodes et champs par défaut. Voir https://stackoverflow.com/a/13319541/14731 et https://stackoverflow.com/a/9256595/14731
@NotNullByDefault
2. Ajoutez l'annotation à chaque package:
package-info.java
MISE À JOUR : Au 12 décembre 2012, le JSR 305 est répertorié comme "Dormant". Selon la documentation:
Il semble que JSR 308 soit en train de devenir JDK 8 et bien que le JSR ne définisse pas @NotNull, l'accompagnant le
Checkers Framework
fait. Au moment d'écrire ces lignes, le plugin Maven est inutilisable en raison de ce bogue: https://github.com/typetools/checker-framework/issues/183la source
Distinguer l'analyse statique de l'analyse d'exécution. Utilisez l'analyse statique pour les éléments internes et l'analyse d'exécution pour les limites publiques de votre code.
Pour les choses qui ne doivent pas être nulles:
Vérification de l'exécution: utilisez "if (x == null) ..." (dépendance zéro) ou @ javax.validation.NotNull (avec validation du bean) ou @ lombok.NonNull (clair et simple) ou guavas Preconditions.checkNotNull (.. .)
Vérification statique: utilisez une annotation @NonNull
Cela devrait donner le meilleur résultat: avertissements dans l'EDI, erreurs par Findbugs et checkerframework, exceptions d'exécution significatives.
Ne vous attendez pas à ce que les vérifications statiques soient matures, leur dénomination n'est pas normalisée et les différentes bibliothèques et IDE les traitent différemment, ignorez-les. Les classes JSR305 javax.annotations. * Ressemblent à la norme, mais elles ne le sont pas, et elles provoquent des packages fractionnés avec Java9 +.
Quelques explications des notes:
Avant Java9, voici ma recommandation:
Notez qu'il n'y a aucun moyen de faire en sorte que Spotbugs émette un avertissement lorsqu'un paramètre de méthode nullable est déréférencé (au moment de la rédaction, la version 3.1 de Spotbugs). Peut-être que checkerframework peut le faire.
Malheureusement, ces annotations ne font pas de distinction entre les cas d'une méthode publique d'une bibliothèque avec des appels arbitraires et des méthodes non publiques où chaque site d'appel peut être connu. Ainsi, la double signification de: "Indiquez que null est indésirable, mais préparez-vous à ce que null soit passé néanmoins" n'est pas possible dans une seule déclaration, par conséquent l'exemple ci-dessus a des annotations différentes pour l'interface et l'implémentation.
Dans les cas où l'approche d'interface fractionnée n'est pas pratique, l'approche suivante est un compromis:
Cela aide les clients à ne pas passer null (écriture du code correct), tout en renvoyant des erreurs utiles s'ils le font.
la source
Eclipse a également ses propres annotations.
Voir sur http://wiki.eclipse.org/JDT_Core/Null_Analysis pour plus de détails.
la source
Je souligne simplement que l'API Java Validation (
javax.validation.constraints.*
) ne comporte pas d'@Nullable
annotation, ce qui est très utile dans un contexte d'analyse statique. Cela a du sens pour la validation du bean d'exécution car c'est la valeur par défaut pour tout champ non primitif en Java (c'est-à-dire rien à valider / appliquer). Aux fins énoncées, cela devrait peser vers les alternatives.la source
Malheureusement,
JSR 308
n'ajoutera pas plus de valeurs que cette suggestion locale de projet non nul iciJava 8
ne viendra pas avec une seule annotation par défaut ou son propreChecker
framework. Semblable à Find-bugs ouJSR 305
, ce JSR est mal entretenu par un petit groupe d'équipes principalement académiques.Aucune puissance commerciale derrière elle,
JSR 308
lance doncEDR 3
(Early Draft Review atJCP
) MAINTENANT, alors qu'ilJava 8
est censé être expédié en moins de 6 mois: -O Similaire à310
btw. mais contrairement à308 Oracle
a pris en charge cela maintenant loin de ses fondateurs pour minimiser les dommages qu'il fera à la plate-forme Java.Chaque projet, fournisseur et classe académique comme ceux derrière le
Checker Framework
etJSR 308
créera sa propre annotation propriétaire de vérificateur.Rendre le code source incompatible pour les années à venir, jusqu'à ce que quelques compromis populaires puissent être trouvés et peut-être ajoutés à
Java 9
ou10
, ou via des cadres commeApache Commons
ouGoogle Guava
;-)la source
Android
Cette réponse est spécifique à Android. Android a un package de support appelé
support-annotations
. Cela fournit des dizaines d' annotations spécifiques à Android et fournit également des annotations courantes commeNonNull
,Nullable
etc.Pour ajouter un package de support-annotations , ajoutez la dépendance suivante dans votre build.gradle:
puis utilisez:
la source
En attendant que cela soit trié en amont (Java 8?), Vous pouvez également simplement définir votre propre projet local
@NotNull
et@Nullable
annotations. Cela peut également être utile si vous travaillez avec Java SE, où iljavax.validation.constraints
n'est pas disponible par défaut.Certes, cela serait largement à des fins décoratives ou à l'épreuve du temps, car ce qui précède n'ajoute évidemment pas en soi un support pour l'analyse statique de ces annotations.
la source
Si vous développez pour Android, vous êtes quelque peu lié à Eclipse (édition: au moment de la rédaction, plus maintenant), qui a ses propres annotations. Il est inclus dans Eclipse 3.8+ (Juno), mais désactivé par défaut.
Vous pouvez l'activer dans Préférences> Java> Compilateur> Erreurs / Avertissements> Analyse nulle (section repliable en bas).
Cochez "Activer l'analyse nulle basée sur les annotations"
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage a des recommandations sur les paramètres. Cependant, si vous avez des projets externes dans votre espace de travail (comme le SDK facebook), ils peuvent ne pas satisfaire ces recommandations, et vous ne voudrez probablement pas les corriger avec chaque mise à jour du SDK ;-)
J'utilise:
la source
@chaqke
.Si vous travaillez sur un grand projet, vous pouvez être mieux de créer vos propres
@Nullable
et / ou@NotNull
annotations.Par exemple:
Si vous utilisez la bonne stratégie de rétention , les annotations ne seront pas disponibles au moment de l'exécution . De ce point de vue, c'est juste une chose interne .
Même si ce n'est pas une science stricte, je pense qu'il est plus logique d'utiliser une classe interne pour cela.
@Nullable
/@NotNull
annotations.Questions supplémentaires (voir commentaires):
Comment configurer cela dans IntelliJ?
la source
idea
ne dites rien à propos devoid test(@NonNull String s) {}
appelé partest(null);
Il y a déjà trop de réponses ici, mais (a) c'est 2019, et il n'y a toujours pas de "standard"
Nullable
et (b) aucune autre réponse ne fait référence à Kotlin.La référence à Kotlin est importante, car Kotlin est 100% interopérable avec Java et il a une fonction de sécurité Null de base. Lors de l'appel de bibliothèques Java, il peut tirer parti de ces annotations pour permettre aux outils Kotlin de savoir si une API Java peut accepter ou retourner
null
.Pour autant que je sache, les seuls
Nullable
packages compatibles avec Kotlin sontorg.jetbrains.annotations
etandroid.support.annotation
(maintenantandroidx.annotation
). Ce dernier est uniquement compatible avec Android, il ne peut donc pas être utilisé dans des projets JVM / Java / Kotlin non Android. Cependant, le package JetBrains fonctionne partout.Donc, si vous développez des packages Java qui devraient également fonctionner dans Android et Kotlin (et être pris en charge par Android Studio et IntelliJ), votre meilleur choix est probablement le package JetBrains.
Maven:
Gradle:
la source
Il existe une autre façon de le faire en Java 8. Je fais 2 choses pour accomplir ce dont j'avais besoin:
java.util.Optional
java.util.Objects.requireNonNull
Exemple:
Donc ma question est, avons-nous même besoin d'annoter lors de l'utilisation de java 8?
Edit: J'ai découvert plus tard que certains considèrent une mauvaise pratique à utiliser
Optional
dans les arguments, il y a une bonne discussion avec les avantages et les inconvénients ici Pourquoi Java 8 en option ne devrait-il pas être utilisé dans les argumentsOption alternative étant donné qu'il n'est pas recommandé d'utiliser Facultatif dans les arguments, nous avons besoin de 2 constructeurs:
la source
new Role(null,null,null,null);
. Avec les annotations, mon IDE et mon analyse statique avertiront que null ne peut pas être transmis à ces paramètres. Sans cela, je ne le découvrirai pas avant d'avoir exécuté le code. Voilà la valeur des annotations.description
non nul et le code client pourrait passer une chaîne vide, mais dans de nombreux cas, il pourrait être pratique de distinguer entre une chaîne vide et de ne pas avoir de valeur. Merci pour votre commentaire. Je mettrai à jour la réponse.Le soleil n'a-t-il pas le leur maintenant? Qu'est-ce que c'est:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
Cela semble être fourni avec toutes les versions de Java que j'ai utilisées au cours des dernières années.
Edit: Comme mentionné dans les commentaires ci-dessous, vous ne voudrez probablement pas les utiliser. Dans ce cas, mon vote est pour les annotations IntelliJ jetbrains!
la source
Une des bonnes choses à propos d'IntelliJ est que vous n'avez pas besoin d'utiliser leurs annotations. Vous pouvez écrire le vôtre ou utiliser ceux de n'importe quel autre outil que vous aimez. Vous n'êtes même pas limité à un seul type. Si vous utilisez deux bibliothèques qui utilisent des annotations @NotNull différentes, vous pouvez dire à IntelliJ de les utiliser toutes les deux. Pour ce faire, allez dans "Configurer les inspections", cliquez sur l'inspection "Conditions constantes et exceptions" et cliquez sur le bouton "Configurer les inspections". J'utilise Nullness Checker partout où je peux, donc j'ai configuré IntelliJ pour utiliser ces annotations, mais vous pouvez le faire fonctionner avec n'importe quel autre outil que vous voulez. (Je n'ai aucune opinion sur les autres outils car j'utilise les inspections d'IntelliJ depuis des années et je les adore.)
la source
Une autre option est les annotations fournies avec ANTLR 4. Suite à la demande d'extraction # 434 , l'artefact contenant les annotations
@NotNull
et@Nullable
inclut un processeur d'annotations qui génère des erreurs et / ou des avertissements au moment de la compilation en cas d'utilisation abusive de l'un de ces attributs (par exemple, si les deux sont appliqués au même élément, ou s'il@Nullable
est appliqué à un élément de type primitif). Le processeur d'annotations fournit une assurance supplémentaire pendant le processus de développement logiciel que les informations transmises par l'application de ces annotations sont exactes, y compris en cas d'héritage de méthode.la source
Si vous construisez votre application à l'aide de Spring Framework, je suggérerais d'utiliser la validation à
javax.validation.constraints.NotNull
partir de Beans Validation empaquetée dans la dépendance suivante:Le principal avantage de cette annotation est que Spring prend en charge à la fois les paramètres de méthode et les champs de classe annotés
javax.validation.constraints.NotNull
. Tout ce que vous devez faire pour activer le support est:fournir le pot api pour la validation des beans et le pot avec l'implémentation du validateur des annotations jsr-303 / jsr-349 (qui vient avec la dépendance Hibernate Validator 5.x):
fournir MethodValidationPostProcessor au contexte de Spring
enfin vous annotez vos classes avec Spring
org.springframework.validation.annotation.Validated
et la validation sera automatiquement gérée par Spring.Exemple:
Lorsque vous essayez d'appeler la méthode doSomething et que vous passez null comme valeur de paramètre, spring (au moyen de HibernateValidator) lance
ConstraintViolationException
. Pas besoin de travaux manuels ici.Vous pouvez également valider les valeurs de retour.
Un autre avantage important du passage
javax.validation.constraints.NotNull
à Beans Validation Framework est qu'il est encore en cours de développement et que de nouvelles fonctionnalités sont prévues pour la nouvelle version 2.0.Et alors
@Nullable
? Il n'y a rien de tel dans Beans Validation 1.1. Eh bien, je pourrais faire valoir que si vous décidez d'utiliser@NotNull
que tout ce qui n'est PAS annoté@NonNull
est effectivement "annulable", l'@Nullable
annotation est donc inutile.la source
Spring 5 a @NonNullApi au niveau du package. Cela semble être un choix pratique pour un projet qui a déjà des dépendances Spring. Tous les champs, paramètres et valeurs de retour par défaut à @NonNull et @Nullable peuvent être appliqués aux quelques endroits qui diffèrent.
Fichier package-info.java:
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations
la source