web-dev-qa-db-fra.com

Quelle annotation @NotNull Java dois-je utiliser?

Je cherche à rendre mon code plus lisible et à utiliser des outils tels que IDE l'inspection de code et/ou l'analyse de code statique (FindBugs et Sonar) afin d'éviter NullPointerExceptions. De nombreux outils semblent incompatibles avec l'annotation _@NotNull_/_@NonNull_/_@Nonnull_ (__) et __ (__) (__) (__) (SOMECODE) __ serait terriblement difficile à lire. Des suggestions de qui est le "meilleur"? Voici la liste des annotations équivalentes que j'ai trouvées:

  • javax.validation.constraints.NotNull
    Créé pour la validation de l'exécution, pas l'analyse statique.
    documentation

  • edu.umd.cs.findbugs.annotations.NonNull
    Utilisé par Findbugs analyse statique et donc Sonar (maintenant Sonarqube )
    documentation

  • javax.annotation.Nonnull
    Cela pourrait également fonctionner avec Findbugs, mais JSR-305 est inactif. (Voir aussi: Quel est le statut de JSR 305? ) source

  • org.jetbrains.annotations.NotNull
    Utilisé par IntelliJ IDEA IDE pour l'analyse statique.
    documentation

  • lombok.NonNull
    Utilisé pour contrôler la génération de code dans Project Lombok .
    Annotation d'espace réservé puisqu'il n'y a pas de standard.
    source , documentation

  • Android.support.annotation.NonNull
    Annotation de marqueur disponible dans Android, fournie par le package support-annotations
    documentation

  • org.Eclipse.jdt.annotation.NonNull
    Utilisé par Eclipse pour l'analyse de code statique
    documentation

888
jaxzin

Puisque JSR 305 (dont le but é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, j'aimerais éviter toute référence à l'EDI, au framework ou à tout toolkit, à l'exception de Java lui-même.

Ceci 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 soit javax.validation.constraints ou javax.annotation. Le premier vient avec JEE. Si c'est mieux que javax.annotation, qui pourrait éventuellement venir avec JSE ou jamais du tout, est un sujet de débat. Personnellement, je préfère javax.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 seule syntaxe qui serait même meilleure: Java.annotation.Nullable. Alors que d'autres paquets passaient javax à Java, javax.annotation serait un pas dans la bonne direction.

La mise en oeuvre

J'espérais qu'ils avaient 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 annotations @NonNull ont toutes la ligne

public @interface NonNull {}

à l'exception de

  • org.jetbrains.annotations qui l'appelle @NotNull et a une implémentation triviale
  • javax.annotation qui a une implémentation plus longue
  • javax.validation.constraints qui l’appelle également @NotNull et a une implémentation

Les annotations @Nullable ont toutes la ligne

public @interface Nullable {}

excepté (encore) les 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

ont tous des annotations d’exécution (@Retention (RUNTIME), tandis que

  • Android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.Eclipse.jdt.annotation
  • org.jetbrains.annotations

ne sont que le temps de compilation (@Retention (CLASS)).

Comme décrit dans this SO answer , l'impact des annotations d'exécution est inférieur à ce que l'on pourrait penser, mais ils présentent l'avantage de permettre aux outils de réaliser des contrôles d'exécution en plus de ceux de la compilation. .

Une autre différence importante est dans le code les annotations peuvent être utilisées. Il y a deux approches différentes. Certains paquets utilisent des contextes de style JLS 9.6.4.1. Le tableau suivant donne un aperçu:

 
 PARAMETRE DE LA METHODE DE CHAMP LOCAL_VARIABLE 
 Android.support.annotation XXX 
 Edu.umd.cs.findbugs.annotations XXXX 
 Org.jetbrains.annotation XXXX 
 Lombok XXXX 
 Javax.validation.constraints XXX 

org.Eclipse.jdt.annotation, javax.annotation et org.checkerframework.checker.nullness.qual utilisent les contextes définis dans JLS 4.11, ce qui, à mon avis, est 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 davantage de détails vous-même, je liste ci-dessous le code de chaque annotation. Pour faciliter la comparaison, j'ai supprimé les commentaires, les importations et l'annotation @Documented. (ils avaient tous @Documented sauf les classes du paquet Android). J'ai réorganisé les lignes et les champs @Target et normalisé les qualifications.

package Android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}

package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package org.Eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}

package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
    When when() default When.ALWAYS;
    static class Checker implements TypeQualifierValidator<Nonnull> {
        public When forConstantValue(Nonnull qualifierqualifierArgument,
                Object value) {
            if (value == null)
                return When.NEVER;
            return When.ALWAYS;
        }
    }
}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
    types = {
        TypeKind.PACKAGE,
        TypeKind.INT,
        TypeKind.BOOLEAN,
        TypeKind.CHAR,
        TypeKind.DOUBLE,
        TypeKind.FLOAT,
        TypeKind.LONG,
        TypeKind.SHORT,
        TypeKind.BYTE
    },
    literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}

Pour être complet, voici les implémentations de @Nullable:

package Android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}

package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}

package org.Eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}

package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
    literals = {LiteralKind.NULL},
    typeNames = {Java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}

Les deux paquets suivants n'ont pas @Nullable, je les énumère donc séparément. Lombok a un @NonNull plutôt ennuyeux. Dans javax.validation.constraints, le @NonNull est en réalité un @NotNull et sa mise en œuvre est longue.

package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
    String message() default "{javax.validation.constraints.NotNull.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        NotNull[] value();
    }
}

Soutien

D'après mon expérience, javax.annotation est au moins pris en charge par Eclipse et par Checker Framework.

Sommaire

Mon annotation idéale serait la syntaxe Java.annotation avec l'implémentation Checker Framework.

Si vous n'avez pas l'intention d'utiliser Checker Framework, le javax.annotation ( JSR-305 ) reste votre meilleur pari. pour le moment.

Si vous êtes prêt à souscrire à Checker Framework, utilisez simplement leur org.checkerframework.checker.nullness.qual.


Sources

  • Android.support.annotation à partir d'Android-5.1.1_r1.jar
  • edu.umd.cs.findbugs.annotations de findbugs-annotations-1.0.0.jar
  • org.Eclipse.jdt.annotation de org.Eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
  • org.jetbrains.annotations de jetbrains-annotations-13.0.jar
  • javax.annotation de gwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qual de checker-framework-2.1.9.Zip
  • lombok de lombok commit f6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraints de validation-api-1.0.0.GA-sources.jar
140
Ludwig Weinzierl

J'aime beaucoup le Checker Framework , qui est une implémentation de type annotations ( JSR-308 ) qui est utilisé pour implémenter des vérificateurs de défauts comme un vérificateur de nullité. Je n'ai pas vraiment essayé de proposer une comparaison, mais je suis satisfait de cette implémentation.

Je ne suis pas affilié au groupe qui propose le logiciel, mais je suis un fan.

Quatre choses que j’aime dans ce système:

  1. Il a un vérificateur de défauts pour nullness (@Nullable), mais en a aussi un pour immuabilité et interning (et autres). J'utilise le premier (nullness) et j'essaie d'utiliser le second (immutability/IGJ). J'essaie le troisième, mais je ne suis pas sûr de l'utiliser à long terme. Je ne suis pas encore convaincu de l'utilité générale des autres contrôleurs, mais il est agréable de savoir que le cadre lui-même est un système permettant de mettre en œuvre une variété d'annotations et de contrôleurs supplémentaires.

  2. Le paramètre par défaut pour la vérification de la nullité fonctionne bien: non nul sauf les locales (NNEL). En gros, cela signifie que le vérificateur traite par défaut chaque élément (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:

    La valeur par défaut de NNEL entraîne le plus petit nombre d'annotations explicites dans votre code.

    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.

  3. Ce framework vous permet d’utiliser avec sans créer de dépendance sur le framework en mettant vos annotations dans un commentaire: par exemple /*@Nullable*/. C'est bien parce que vous pouvez annoter et vérifier une bibliothèque ou un code partagé, tout en pouvant 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 framework Checker sur tous mes projets.

  4. La structure a un moyen de annoter les API que vous utilisez et que vous n’avez pas encore annoté pour la nullité en utilisant des fichiers de raccord.

86
Bert F

J'utilise celui d'IntelliJ, parce que je m'inquiète surtout du fait qu'IntelliJ signale des éléments susceptibles de générer un NPE. Je conviens qu'il est frustrant de ne pas avoir une annotation standard dans le JDK. On parle de l'ajouter, cela pourrait le rendre dans Java 7. Dans ce cas, il y en aura un de plus à choisir!

53
Sam Barnum

Selon la liste des fonctionnalités Java 7 , les annotations de type JSR-308 sont différées sur Java 8. Les annotations JSR-305 ne sont même pas mentionnées.

Il y a quelques informations sur l'état de JSR-305 dans un annexe de la dernière version de JSR-308. Cela inclut l'observation selon laquelle les annotations JSR-305 semblent être abandonnées. La page JSR-305 indique également qu'il est "inactif".

En attendant, la réponse pragmatique consiste à utiliser les types d'annotation pris en charge par les outils les plus largement utilisés ... et à être prêt à les modifier si la situation change.


En fait, JSR-308 ne définit aucun type/classe d'annotation, et il semble qu'ils pensent que cela est hors de portée. (Et ils ont raison, étant donné l'existence de JSR-305).

Cependant, si JSR-308 a vraiment l’intention de passer à Java 8, cela ne me surprendrait pas si l’intérêt pour JSR-305 était ravivé. Autant que je sache, l'équipe JSR-305 n'a pas officiellement abandonné son travail. Ils viennent d'être 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 auteurs de FindBugs.

32
Stephen C

Pour les projets Android, vous devez utiliser Android.support.annotation.NonNull et Android.support.annotation.Nullable. Ces annotations utiles, ainsi que d’autres spécifiques à Android, sont disponibles dans = Bibliothèque de support .

De http://tools.Android.com/tech-docs/support-annotations :

La bibliothèque de support elle-même a également été annotée avec ces annotations. Ainsi, en tant qu'utilisateur de la bibliothèque de support, Android Studio vérifie déjà votre code et signale les problèmes potentiels en fonction de ces annotations.

26
James Wald

Si quelqu'un ne cherche que les classes IntelliJ: vous pouvez les obtenir à partir du référentiel maven avec

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 
19
Bruno Eberhard

JSR305 et FindBugs sont créés par la même personne. Les deux sont mal entretenus mais sont aussi standard que possible et sont supportés par tous les principaux IDE. La bonne nouvelle 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

  1. Définir @NotNullByDefault
import Java.lang.annotation.Documented;
import Java.lang.annotation.ElementType;
import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;


    /**
     * This annotation can be applied to a package, class or method to indicate that the class fields,
     * method return types and parameters in that element are not null by default unless there is: <ul>
     * <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
     * case the annotation of the corresponding parameter in the superclass applies) <li> there is a
     * default parameter annotation applied to a more tightly nested element. </ul>
     * <p/>
     * @see https://stackoverflow.com/a/9256595/14731
     */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
    {
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.FIELD,
        ElementType.LOCAL_VARIABLE,
        ElementType.METHOD,
        ElementType.PACKAGE,
        ElementType.PARAMETER,
        ElementType.TYPE
    })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NotNullByDefault
    {
    }

2. Ajoutez l'annotation à chaque package: package-info.Java

@NotNullByDefault
package com.example.foo;

UPDATE: Au 12 décembre 2012 JSR 305 est répertorié comme "Dormant". Selon la documentation:

Une JSR qui a été votée comme "dormante" par le Comité exécutif ou qui a atteint la fin de sa vie naturelle.

Il semble que JSR 308 est en cours de création du JDK 8 et bien que le JSR ne définisse pas @NotNull, le Checkers Framework fait. Au moment de la rédaction de cet article, le plugin Maven est inutilisable à cause de ce bogue: https://github.com/typetools/checker-framework/issues/18

18
Gili

Eclipse a aussi ses propres annotations.

org.Eclipse.jdt.annotation.NonNull

Voir à http://wiki.Eclipse.org/JDT_Core/Null_Analysis pour plus de détails.

12
Horcrux7

Signalez simplement que l'API de validation Java (javax.validation.constraints.*) n'est pas accompagnée d'une annotation @Nullable, ce qui est très utile dans un contexte d'analyse statique. Il est logique de valider un bean d'exécution, car il s'agit de la valeur par défaut pour tout champ non primitif dans Java (c'est-à-dire rien à valider/appliquer). Aux fins indiquées, cela devrait peser par rapport aux alternatives.

11
Ophir Radnitz

Malheureusement, JSR 308 n’ajoutera pas plus de valeurs que la suggestion locale du projet Null ici

Java 8 ne viendra pas avec une seule annotation par défaut ou son propre cadre Checker. Semblable à Find-Bugs ou à JSR 305, cette JSR est mal entretenue par un petit groupe d’équipes essentiellement universitaires.

Aucune puissance commerciale derrière elle, donc JSR 308 lance EDR 3 (version préliminaire révisée à JCP) NOW, alors que Java 8 est censé être livré dans moins de 6 mois: -O Similaire à 310 btw. mais contrairement à 308 Oracle a pris ses responsabilités à l'écart de ses fondateurs afin de minimiser les dommages que cela causerait à la Java Plateforme.

Chaque projet, fournisseur et classe académique comme ceux derrière le Checker Framework et JSR 308 créeront leur propre annotation de vérificateur propriétaire.

Rendre le code source incompatible pour les années à venir, jusqu'à ce que quelques compromis populaires puissent être trouvés et éventuellement ajoutés à Java 9 ou 10, ou via des cadres tels que Apache Commons ou Google Guava; - )

7
Werner Keil

Android

Cette réponse est spécifique à Android. Android a un package de support appelé support-annotations. Cela fournit des dizaines de spécifique à Android annotations et fournit également les plus courantes comme NonNull, Nullable etc.

Pour ajouter le package support-annotations , ajoutez la dépendance suivante dans votre build.gradle:

compile 'com.Android.support:support-annotations:23.1.1'

et ensuite utiliser:

import Android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}
7
Shubham Chaudhary

Faites la distinction entre l'analyse statique et 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 devraient 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 goyave Preconditions.checkNotNull (.. .)

    • Utilisez Facultatif pour les types de renvoi de méthode (uniquement). Java8 ou Guava.
  • Vérification statique: Utiliser une annotation @NonNull

  • Lorsque cela vous convient, utilisez les annotations @ ... NonnullByDefault au niveau de la classe ou du package. Créez vous-même ces annotations (il est facile de trouver des exemples).
    • Sinon, utilisez @ ... CheckForNull sur les retours de méthode pour éviter les NPE

Cela devrait donner le meilleur résultat: avertissements dans l'EDI, erreurs de Findbugs et checkerframework, exceptions d'exécution significatives.

Ne vous attendez pas à ce que les vérifications statiques soient matures, leur nom n'est pas normalisé et différentes bibliothèques et IDE les traitent différemment, ignorez-les. Les classes javax.annotations. * JSR305 ressemblent à des normes, mais elles ne le sont pas et entraînent la scission de packages avec Java9 +.

Quelques explications sur les notes:

  • Les annotations Findbugs/spotbugs/jsr305 avec le package javax.validation. * Entrent en conflit avec d'autres modules de Java9 + et enfreignent éventuellement la licence Oracle.
  • Les annotations Spotbugs dépendent toujours des annotations jsr305/findbugs lors de la compilation (au moment de la rédaction du présent document https://github.com/spotbugs/spotbugs/issues/421 )
  • jetbrains @NotNull nom est en conflit avec @ javax.validation.NotNull.
  • les annotations jetbrains, Eclipse ou checkersframework pour la vérification statique ont l'avantage sur javax.annotations de ne pas entrer en conflit avec d'autres modules dans Java9 et versions ultérieures
  • @ javax.annotations.Nullable ne signifie pas pour Findbugs/Spotbugs ce que vous (ou votre IDE) pensez que cela signifie. Findbugs l'ignorera (sur les membres). Triste, mais vrai ( https://sourceforge.net/p/findbugs/bugs/1181 )
  • Pour le contrôle statique en dehors d'un IDE, 2 outils gratuits existent: Spotbugs (anciennement Findbugs) et checkersframework.
  • La bibliothèque Eclipse a @NonNullByDefault, jsr305 uniquement @ParametersAreNonnullByDefault. Ce ne sont que des simples wrappers appliquant des annotations de base à tout ce qui est contenu dans un package (ou une classe). Vous pouvez facilement créer les vôtres. Ceci peut être utilisé sur un paquet. Cela peut entrer en conflit avec le code généré (par exemple, lombok).
  • Les annotations Eclipse jdt ne sont pas applicables aux retours de méthode statiques ni à d'autres cas.
  • L'utilisation de lombok en tant que dépendance exportée doit être évitée pour les bibliothèques que vous partagez avec d'autres personnes, moins il existe de dépendances transitives, mieux c'est.
  • L'utilisation du cadre de validation Bean est puissante, mais requiert une surcharge de temps. Il est donc excessif d'éviter tout contrôle manuel des valeurs nuls.
  • L'utilisation de facultatif pour les champs et les paramètres de méthode est controversée (vous pouvez facilement y trouver des articles)
  • Les annotations null Android font partie de la bibliothèque de support Android, elles viennent avec beaucoup d'autres classes et ne fonctionnent pas bien avec d'autres annotations/outils.

Avant Java9, voici ma recommandation:

// file: package-info.Java
@javax.annotation.ParametersAreNonnullByDefault
package example;


// file: PublicApi
package example;

public class PublicApi {

    /**
     * @param firstname MUST NOT be null
     * @param lastname MUST NOT be null
     */
    public Person createPerson(
            // Spotbugs ignores the param annotations, but IDEs will show problems
            @Nullable String firstname, // Users  might send null
            @Nullable String lastname // Users might send null
            ) {
        if (firstname == null) throw new IllagalArgumentException(...);
        if (lastname == null) throw new IllagalArgumentException(...);
        return doCreatePerson(fistname, lastname, nickname);
    }

    @NonNull // Spotbugs checks that method cannot return null
    private Person doCreatePerson(
             String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
             String lastname,
             @Nullable String nickname // tell Spotbugs null is ok
             ) {
         return new Person(firstname, lastname, nickname);
    }

    @CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
    private Person getNickname(
         String firstname,
         String lastname) {
         return NICKNAMES.get(firstname + ':' + lastname);
    }
}

Notez qu’il n’ya aucun moyen de faire en sorte que Spotbugs lève un avertissement lorsqu’un paramètre de méthode nullable est déréférencé (au moment de l’écriture, la version 3.1 de Spotbugs). Peut-être que checkerframework peut le faire.

6
tkruse

En attendant que cela soit trié en amont (Java 8?), Vous pouvez également définir vos propres annotations @NotNull et @Nullable locales au projet. Cela peut être utile également si vous travaillez avec Java SE, où javax.validation.constraintsn'est pas disponible par défaut.

import Java.lang.annotation.*;

/**
 * Designates that a field, return value, argument, or variable is
 * guaranteed to be non-null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}

/**
 * Designates that a field, return value, argument, or variable may be null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}

Certes, cela servirait en grande partie à des fins décoratives ou d’avenir, étant donné que ce qui précède n’affiche en soi aucun support pour l’analyse statique de ces annotations.

5
Arto Bendiken

Si vous travaillez sur un gros projet, vous feriez mieux de créer vos propres annotations @Nullable et/ou @NotNull.

Par exemple:

@Java.lang.annotation.Documented
@Java.lang.annotation.Retention(Java.lang.annotation.RetentionPolicy.CLASS)
@Java.lang.annotation.Target({Java.lang.annotation.ElementType.FIELD,
                              Java.lang.annotation.ElementType.METHOD,    
                              Java.lang.annotation.ElementType.PARAMETER,
                              Java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable 
{
}

Si vous utilisez la bonne politique 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 .

Bien que ce ne soit pas une science stricte, je pense qu'il est plus logique d'utiliser une classe interne pour cela.

  • C'est une chose interne. (pas d'impact fonctionnel ou technique)
  • Avec beaucoup, beaucoup d'usages.
  • Les IDE comme IntelliJ supportent les annotations @Nullable/@NotNull personnalisées.
  • La plupart des frameworks préfèrent utiliser leur propre version interne.

Questions supplémentaires (voir commentaires):

Comment configurer cela dans IntelliJ?

Cliquez sur "l'officier de police" dans le coin inférieur droit de la barre d'état IntelliJ. Et cliquez sur "Configurer les inspections" dans la fenêtre contextuelle. Suivant ... configure annotations

4
bvdb

Si vous développez pour Android, vous êtes un peu lié à Eclipse (édition: au moment de l'écriture, pas plus), 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 réductible en bas).

Cochez "Activer l'analyse des valeurs nulles par annotation"

http://wiki.Eclipse.org/JDT_Core/Null_Analysis#Usage a des recommandations sur les paramètres. Toutefois, si vous avez des projets externes dans votre espace de travail (tel que le SDK de Facebook), ils risquent de ne pas satisfaire à ces recommandations et vous ne voudrez probablement pas les corriger à chaque mise à jour du SDK ;-)

J'utilise:

  1. Accès nul au pointeur: Erreur
  2. Violation de la spécification null: Error (lié au point n ° 1)
  3. Accès potentiel à un pointeur nul: Avertissement (sinon, le SDK de Facebook aurait des avertissements)
  4. Conflit entre annotations nulles et inférence nulle: Avertissement (lié au point 3)
4
chaqke

Il y a une autre façon de faire cela dans Java 8. Je fais 2 choses pour accomplir ce dont j'avais besoin:

  1. Rendre les champs nullables explicites avec les types en encapsulant les champs nullables avec Java.util.Optional
  2. Vérification que tous les champs non nullables ne sont pas nuls au moment de la construction avec Java.util.Objects.requireNonNull

Exemple:

import static Java.util.Objects.requireNonNull;

public class Role {

  private final UUID guid;
  private final String domain;
  private final String name;
  private final Optional<String> description;

  public Role(UUID guid, String domain, String name, Optional<String> description) {
    this.guid = requireNonNull(guid);
    this.domain = requireNonNull(domain);
    this.name = requireNonNull(name);
    this.description = requireNonNull(description);
  }

Ma question est donc la suivante: devons-nous même annoter lorsque vous utilisez Java 8?

Edit: j’ai découvert plus tard que certains considéraient qu’une mauvaise pratique consistait à utiliser Optional dans les arguments, il y a une bonne discussion avec les avantages et les inconvénients ici Pourquoi devrait-on utiliser Java 8? Facultatif ne pas être utilisé en arguments

3

Il y a déjà trop de réponses ici, mais (a) nous sommes en 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 dispose d'une fonctionnalité de base Null Safety. Lors de l'appel des bibliothèques Java, il peut tirer parti de ces annotations pour permettre aux outils Kotlin de savoir si une API Java peut accepter ou renvoyer null.

Autant que je sache, les seuls packages Nullable compatibles avec Kotlin sont org.jetbrains.annotations et Android.support.annotation (maintenant androidx.annotation). Ce dernier est uniquement compatible avec Android et 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 JetBrains. paquet.

Maven:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations-Java5</artifactId>
    <version>15.0</version>
</dependency>

Gradle:

implementation 'org.jetbrains:annotations-Java5:15.0'
2
noamtm

Si vous construisez votre application à l'aide de Spring Framework, je suggérerais d'utiliser _javax.validation.constraints.NotNull_ provenant de validation de beans empaqueté dans la dépendance suivante:

_    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
_

Le principal avantage de cette annotation est que Spring prend en charge les paramètres de méthode et les champs de classe annotés de _javax.validation.constraints.NotNull_. Pour activer le support, il vous suffit de:

  1. fournissez le fichier api jar pour la validation des beans et le fichier jar avec l'implémentation du validateur des annotations jsr-303/jsr-349 (fourni avec la dépendance Hibernate Validator 5.x):

    _<dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
    _
  2. fournit MethodValidationPostProcessor au contexte de spring

    _  @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
    _
  3. enfin, vous annotez vos classes avec Spring org.springframework.validation.annotation.Validated et la validation sera automatiquement gérée par Spring.

Exemple:

_@Service
@Validated
public class MyServiceImpl implements MyService {

  @Override
  public Something doSomething(@NotNull String myParameter) {
        // No need to do something like assert myParameter != null  
  }
}
_

Lorsque vous essayez d'appeler la méthode doSomething et que vous indiquez null comme valeur de paramètre, spring (au moyen de HibernateValidator) renvoie ConstraintViolationException. Pas besoin de travail manuel ici.

Vous pouvez également valider les valeurs de retour.

Un autre avantage important de _javax.validation.constraints.NotNull_ pour Beans Validation Framework est qu’il est toujours en cours de développement et que de nouvelles fonctionnalités sont prévues pour la nouvelle version 2.0.

Qu'en est-il de _@Nullable_? Il n'y a rien de tel dans Beans Validation 1.1. Eh bien, je pourrais soutenir que si vous décidez d'utiliser _@NotNull_, tout ce qui n'est PAS annoté avec _@NonNull_ est effectivement "nullable", l'annotation _@Nullable_ est donc inutile.

2
walkeros

Sun n'a-t-il pas le leur maintenant? Qu'est-ce que c'est ça:
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 voulez probablement pas les utiliser. Dans ce cas, je vote pour les annotations IntelliJ sur les jetbrains!

2
Nate W.

Les annotations fournies avec ANTLR 4 constituent une autre option. Suite à demande d'extraction n ° 434 , l'artefact contenant les annotations @NotNull et @Nullable inclut un processeur d'annotation qui génère des erreurs de compilation et/ou des avertissements dans le cas où l'un de ces attributs est mal utilisé (par exemple, si les deux sont appliqués au même élément ou si @Nullable est appliqué à un élément de type primitif). Le processeur d'annotation fournit une assurance supplémentaire lors du processus de développement logiciel que les informations véhiculées par l'application de ces annotations sont exactes, y compris en cas d'héritage de méthode.

1
Sam Harwell

L'un des avantages de IntelliJ est qu'il n'est pas nécessaire d'utiliser leurs annotations. Vous pouvez écrire le vôtre, ou vous pouvez 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 indiquer à IntelliJ de les utiliser toutes les deux. Pour ce faire, allez dans "Configurer les inspections", cliquez sur l'inspection "Conditions constantes et exceptions", puis sur le bouton "Configurer les inspections". J'utilise le vérificateur de nullité chaque fois que je le peux. J'ai donc configuré IntelliJ pour utiliser ces annotations, mais vous pouvez le faire fonctionner avec n'importe quel autre outil de votre choix. (Je n'ai pas d'opinion sur les autres outils car j'utilise les inspections d'IntelliJ depuis des années et je les adore.)

1
MiguelMunoz