web-dev-qa-db-fra.com

Éviter! = Déclarations nulles

J'utilise beaucoup object != null pour éviter NullPointerException .

Y a-t-il une bonne alternative à cela? 

Par exemple:

if (someobject != null) {
    someobject.doCalc();
}

Cela évite une NullPointerException, quand il est inconnu si l'objet est null ou non.

Notez que la réponse acceptée peut être obsolète, voir https://stackoverflow.com/a/2386013/12943 pour une approche plus récente.

3729
Goran Martinic

Pour moi, cela ressemble à un problème assez commun auquel les développeurs débutants à intermédiaires ont tendance à être confrontés à un moment donné: ils ne savent pas ou ne font pas confiance aux contrats auxquels ils participent et sur-vérifient de manière défensive la nullité. De plus, lorsqu'ils écrivent leur propre code, ils ont tendance à compter sur le renvoi de valeurs NULL pour indiquer quelque chose, ce qui oblige l'appelant à vérifier les valeurs NULL.

En d'autres termes, il y a deux cas où la vérification de null survient:

  1. Où null est une réponse valide en termes de contrat; et

  2. Où ce n'est pas une réponse valide.

(2) est facile. Utilisez des instructions assert (assertions) ou autorisez un échec (par exemple, NullPointerException ). Les assertions sont une fonctionnalité Java très sous-utilisée ajoutée dans la version 1.4. La syntaxe est la suivante:

assert <condition>

ou

assert <condition> : <object>

<condition> est une expression booléenne et <object> est un objet dont le résultat de la méthode toString() sera inclus dans l'erreur.

Une instruction assert génère une Error (AssertionError) si la condition n'est pas vraie. Par défaut, Java ignore les assertions. Vous pouvez activer les assertions en transmettant l'option -ea à la machine virtuelle Java. Vous pouvez activer et désactiver des assertions pour des classes et des packages individuels. Cela signifie que vous pouvez valider le code avec les assertions lors du développement et des tests, et les désactiver dans un environnement de production, bien que mes tests n'aient montré aucun impact sur les performances des assertions.

Ne pas utiliser d'assertions dans ce cas est correct car le code va simplement échouer, ce qui se produira si vous utilisez des assertions. La seule différence est qu'avec les affirmations, cela peut arriver plus tôt, de manière plus significative et éventuellement avec des informations supplémentaires, ce qui peut vous aider à comprendre pourquoi cela s'est produit si vous ne vous y attendiez pas.

(1) est un peu plus difficile. Si vous n'avez aucun contrôle sur le code que vous appelez, vous êtes bloqué. Si null est une réponse valide, vous devez la vérifier.

Si c'est le code que vous contrôlez cependant (et c'est souvent le cas), c'est une autre histoire. Évitez d’utiliser des valeurs NULL en réponse. Avec les méthodes qui renvoient des collections, rien de plus simple: renvoyez des collections vides (ou des tableaux) au lieu de null à peu près tout le temps.

Avec les non-collections, cela pourrait être plus difficile. Considérez ceci comme un exemple: si vous avez ces interfaces:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

où Parser prend une entrée utilisateur brute et trouve quelque chose à faire, peut-être si vous implémentez une interface de ligne de commande pour quelque chose. Maintenant, vous pouvez indiquer au contrat qu'il renvoie null s'il n'y a pas d'action appropriée. Cela mène à la vérification de nullité dont vous parlez.

Une autre solution consiste à ne jamais renvoyer null et à utiliser le modèle Null Object :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

Comparer:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

à

ParserFactory.getParser().findAction(someInput).doSomething();

ce qui est un design bien meilleur car il conduit à un code plus concis.

Cela dit, il est peut-être tout à fait approprié que la méthode findAction () lève une exception avec un message d'erreur significatif, en particulier dans le cas où vous vous fiez aux entrées de l'utilisateur. Il serait bien mieux que la méthode findAction lève une exception plutôt que que la méthode appelante explose avec une simple exception NullPointerException sans explication.

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

Ou, si vous pensez que le mécanisme try/catch est trop laid, plutôt que de ne rien faire, votre action par défaut devrait fournir un retour à l'utilisateur.

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}
2487
cletus

Si vous utilisez (ou prévoyez d’utiliser) un Java IDE comme JetBrains IntelliJ IDEA , Eclipse ou Netbeans ou un outil comme findbugs, vous pouvez utiliser des annotations pour résoudre ce problème.

En gros, vous avez @Nullable et @NotNull.

Vous pouvez utiliser la méthode et les paramètres, comme ceci:

@NotNull public static String helloWorld() {
    return "Hello World";
}

ou

@Nullable public static String helloWorld() {
    return "Hello World";
}

Le deuxième exemple ne compilera pas (dans IntelliJ IDEA).

Lorsque vous utilisez la première fonction helloWorld() dans un autre morceau de code:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

Maintenant, le compilateur IntelliJ IDEA vous dira que la vérification est inutile, puisque la fonction helloWorld() ne renverra jamais null.

En utilisant paramètre

void someMethod(@NotNull someParameter) { }

si vous écrivez quelque chose comme:

someMethod(null);

Cela ne compilera pas.

Dernier exemple utilisant @Nullable

@Nullable iWantToDestroyEverything() { return null; }

Ce faisant

iWantToDestroyEverything().something();

Et vous pouvez être sûr que cela n'arrivera pas. :)

C'est une bonne façon de laisser le compilateur vérifier quelque chose de plus que d'habitude et de renforcer vos contrats. Malheureusement, ce n'est pas supporté par tous les compilateurs.

Dans IntelliJ IDEA 10.5 et versions ultérieures, ils ont ajouté la prise en charge de toute autre implémentation @Nullable@NotNull.

Voir l'article de blog Annotations @ Nullable/@ NotNull plus flexibles et configurables.

559
Luca Molteni

Si les valeurs nulles ne sont pas autorisées

Si votre méthode est appelée en externe, commencez par quelque chose comme ceci:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

Ensuite, dans le reste de cette méthode, vous saurez que object n'est pas null.

S'il s'agit d'une méthode interne (ne faisant pas partie d'une API), indiquez simplement qu'elle ne peut pas être nulle et c'est tout.

Exemple:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

Cependant, si votre méthode ne fait que transmettre la valeur, et que la méthode suivante la transmet, etc., cela pourrait devenir problématique. Dans ce cas, vous pouvez vérifier l'argument comme ci-dessus.

Si null est autorisé

Cela dépend vraiment. Si trouve que je fais souvent quelque chose comme ça:

if (object == null) {
  // something
} else {
  // something else
}

Alors je branche, et fais deux choses complètement différentes. Il n'y a pas d'extrait de code laid, car je dois vraiment faire deux choses différentes en fonction des données. Par exemple, devrais-je travailler sur l'entrée ou devrais-je calculer une bonne valeur par défaut?


En fait, il est rare que j'utilise l'idiome "if (object != null && ...".

Il peut être plus facile de vous donner des exemples, si vous montrez des exemples d’emplacements typiques de l’idiome.

296
myplacedk

Wow, je déteste presque ajouter une autre réponse quand nous avons 57 façons différentes de recommander le NullObject pattern, mais je pense que certaines personnes intéressées par cette question voudront peut-être savoir qu'il existe une proposition sur la table pour Java 7 d'ajouter "null-safe handling" — une syntaxe simplifiée pour la logique if-not-equal-null.

L'exemple donné par Alex Miller ressemble à ceci:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

?. signifie que l’identifiant de gauche n’est référencé que s’il n’est pas nul, sinon, le reste de l’expression est évalué à null. Certaines personnes, comme Dick Wall, membre de Java Posse, et les { électeurs de Devoxx aiment beaucoup cette proposition, mais il y a aussi une opposition, car cela encouragera davantage l'utilisation de null comme valeur sentinelle.


Mise à jour: Une proposition officielle pour un opérateur null-safe en Java 7 a été soumise sous Project Coin. La syntaxe est un peu différente de l'exemple ci-dessus, mais la même notion.


Mise à jour: La proposition de l'opérateur null-safe n'a pas été intégrée à Project Coin. Donc, vous ne verrez pas cette syntaxe dans Java 7.

222
erickson

Si les valeurs non définies ne sont pas autorisées:

Vous pouvez configurer votre IDE pour vous avertir d'un possible déréférencement nul. Par exemple. Dans Eclipse, voir Préférences> Java> Compilateur> Analyse des erreurs/avertissements/Null.

Si des valeurs indéfinies sont autorisées:

Si vous souhaitez définir une nouvelle API dans laquelle des valeurs non définies ont un sens, utilisez l'option Option Pattern (peut être familier des langages fonctionnels). Il présente les avantages suivants:

  • L'API indique explicitement si une entrée ou une sortie existe ou non.
  • Le compilateur vous oblige à gérer le cas "non défini".
  • Option est une monade , il n’est donc pas nécessaire de vérifier les valeurs de base, utilisez simplement map/foreach/getOrElse ou un combinateur similaire pour utiliser en toute sécurité la valeur (exemple) .

Java 8 a une classe Optional class (recommandée); pour les versions antérieures, il existe des alternatives de bibliothèque, par exemple Guava 's Optional ou FunctionalJava ' s Option . Mais comme beaucoup de modèles de style fonctionnel, utiliser Option en Java (même 8) donne un certain nombre de standards, que vous pouvez réduire avec un langage JVM moins détaillé, par exemple. Scala ou Xtend.

Si vous devez utiliser une API susceptible de renvoyer null, vous ne pouvez pas faire grand chose en Java. Xtend et Groovy ont les opérateurs Elvis?: et l'opérateur de déréférence null-safe?., mais notez que cette fonction renvoie la valeur null dans le cas d'une référence null. Par conséquent, elle "diffère" le traitement correct de null.

184
thSoft

Seulement pour cette situation -

Ne pas vérifier si une variable est nulle avant d'appeler une méthode equals (un exemple de comparaison de chaîne ci-dessous):

if ( foo.equals("bar") ) {
 // ...
}

entraînera une NullPointerException si foo n'existe pas.

Vous pouvez éviter cela si vous comparez votre Strings comme ceci:

if ( "bar".equals(foo) ) {
 // ...
}
169
echox

Avec Java 8, la nouvelle classe Java.util.Optional permet de résoudre une partie du problème. On peut au moins dire que cela améliore la lisibilité du code et, dans le cas des API publiques, clarifie le contrat de l'API pour le développeur client.

Ils travaillent comme ça:

Un objet facultatif pour un type donné (Fruit) est créé en tant que type de retour d'une méthode. Il peut être vide ou contenir un objet Fruit:

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

Maintenant, regardez ce code où nous recherchons une liste de Fruit (fruits) pour une instance Fruit donnée:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

Vous pouvez utiliser l'opérateur map() pour effectuer un calcul - ou extraire une valeur - d'un objet facultatif. orElse() vous permet de fournir une solution de secours pour les valeurs manquantes.

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

Bien entendu, le contrôle de la valeur null/vide est toujours nécessaire, mais au moins le développeur est conscient du fait que la valeur peut être vide et que le risque d'oubli du contrôle est limité.

Dans une API créée à partir de zéro en utilisant Optional chaque fois qu'une valeur de retour peut être vide et renvoyant un objet brut uniquement lorsqu'il ne peut pas s'agir de null (convention), le code client peut abandonner les vérifications nulles sur les valeurs de retour d'objet simple ...

Bien sûr, Optional pourrait également être utilisé comme argument de méthode, peut-être un meilleur moyen d’indiquer des arguments optionnels que 5 ou 10 méthodes de surcharge dans certains cas.

Optional offre d'autres méthodes pratiques, telles que orElse qui permettent d'utiliser une valeur par défaut et ifPresent qui fonctionne avec expressions lambda .

Je vous invite à lire cet article (ma source principale pour la rédaction de cette réponse) dans lequel la problématique NullPointerException (et en général le pointeur nul) ainsi que la solution (partielle) apportée par Optional sont bien expliquées: Objets facultatifs Java.

148
Pierre Henry

Selon le type d’objet que vous vérifiez, vous pourrez peut-être utiliser certaines des classes du bien commun Apache telles que: Apache commons lang et Apache commons collections

Exemple: 

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

ou (selon ce que vous devez vérifier):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

La classe StringUtils n'est qu'un parmi beaucoup d'autres. il y a pas mal de bonnes classes dans les communes qui font de la manipulation sans risque.

Voici un exemple d'utilisation de la validation nulle en Java lorsque vous incluez la bibliothèque Apache (commons-lang-2.4.jar)

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

Et si vous utilisez Spring, Spring possède également les mêmes fonctionnalités dans son package, voir bibliothèque (spring-2.4.6.jar) 

Exemple d'utilisation de ce classf statique à partir de spring (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
119
javamonkey79
  • Si vous considérez qu'un objet ne doit pas être nul (ou s'il s'agit d'un bogue), utilisez une assertion.
  • Si votre méthode n'accepte pas les paramètres NULL, dites-le dans le fichier javadoc et utilisez une assertion.

Vous devez vérifier pour object! = Null que si vous voulez gérer le cas où l'objet peut être null ...

Il est proposé d’ajouter de nouvelles annotations dans Java7 pour aider les paramètres null/notnull: http://tech.puredanger.com/Java7/#jsr308

91
pgras

Je suis fan du code "fail fast". Demandez-vous - faites-vous quelque chose d'utile dans le cas où le paramètre est nul? Si vous n'avez pas de réponse claire à ce que votre code devrait faire dans ce cas ... I.e. elle ne devrait jamais être nulle en premier lieu, alors ignorez-la et laissez une exception NullPointerException être levée. Le code d'appel donnera tout autant de sens à un NPE qu'à un IllegalArgumentException, mais il sera plus facile pour le développeur de déboguer et de comprendre ce qui s'est mal passé si un NPE est lancé plutôt que votre code essayant d'exécuter une autre imprévu logique - ce qui a finalement pour résultat que l'application échoue quand même. 

85
Alex Worden

Le cadre de gestion des collections de Google offre un moyen élégant et efficace de réaliser le contrôle nul.

Il y a une méthode dans une classe de bibliothèque comme ceci:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

Et l'utilisation est (avec import static):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

Ou dans votre exemple:

checkNotNull(someobject).doCalc();
72
user2427

Parfois, vous avez des méthodes qui opèrent sur ses paramètres qui définissent une opération symétrique:

a.f(b); <-> b.f(a);

Si vous savez que b ne peut jamais être nul, vous pouvez simplement l'échanger. C'est le plus utile pour les égaux: Au lieu de foo.equals("bar"); mieux faire "bar".equals(foo);.

71

Plutôt que le motif d'objet Null (qui a ses utilisations), vous pouvez envisager des situations où l'objet null est un bogue.

Lorsque l'exception est levée, examinez la trace de la pile et corrigez le bogue.

69
Jim Nelson

Null n'est pas un "problème". Il fait partie intégrante d'un ensemble d'outils de modélisation complet . Le logiciel vise à modéliser la complexité du monde et à supporter son fardeau. Null indique 'Pas de données' ou 'Inconnu' dans Java et similaires. Il est donc approprié d'utiliser des valeurs NULL à ces fins. Je ne préfère pas le motif 'Null object'; Je pense que cela soulève le problème ' qui gardera les gardiens '.
Si vous me demandez quel est le nom de ma petite amie, je vous dirai que je n’ai pas de petite amie. Dans le langage Java, je renverrai null. Une alternative serait de lancer une exception significative pour indiquer un problème qui ne peut pas (ou ne veut pas être) être résolu ici et le déléguer quelque part plus haut dans la pile pour réessayer ou signaler une erreur d'accès aux données à l'utilisateur.

  1. Pour une 'question inconnue', donnez 'réponse inconnue'. (Soyez null-safe si cela est correct du point de vue commercial) La vérification des arguments pour null une fois dans une méthode avant que l'utilisation n'empêche plusieurs appelants de les vérifier avant un appel.

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }
    

    Précédent mène au flux logique normal pour obtenir aucune photo d'une petite amie inexistante de ma photothèque.

    getPhotoOfThePerson(me.getGirlfriend())
    

    Et cela correspond à la nouvelle API Java à venir (dans l’avenir)

    getPhotoByName(me.getGirlfriend()?.getName())
    

    Bien que ce soit plutôt une "affaire normale" de ne pas trouver une photo stockée dans la base de données pour une personne, j’avais l'habitude d'utiliser des paires comme ci-dessous pour d'autres cas.

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);
    

    Et n'aimez pas taper <alt> + <shift> + <j> (générer javadoc dans Eclipse) et écrire trois mots supplémentaires pour votre API publique. Ce sera plus que suffisant pour tous sauf ceux qui ne lisent pas la documentation.

    /**
     * @return photo or null
     */
    

    ou

    /**
     * @return photo, never null
     */
    
  2. Ceci est un cas plutôt théorique et dans la plupart des cas, vous devriez préférer Java une API null safe (au cas où elle sera disponible dans 10 ans), mais NullPointerException est une sous-classe d'un Exception. C'est donc une forme de Throwable qui indique les conditions qu'une application raisonnable pourrait vouloir intercepter ( javadoc )! Pour utiliser le premier avantage des exceptions et séparer le code de traitement des erreurs du code "normal" ( selon les créateurs de Java ), il convient, comme pour moi, d'intercepter NullPointerException.

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }
    

    Des questions pourraient se poser:

    Q. Que se passe-t-il si getPhotoDataSource() renvoie null?
    UNE. Cela dépend de la logique métier. Si je ne parviens pas à trouver un album photo, je ne vous montrerai aucune photo. Et si appContext n'est pas initialisé? La logique métier de cette méthode résout ce problème. Si la même logique doit être plus stricte, une exception est générée dans la logique métier et une vérification explicite de null doit être utilisée (cas 3). L'API [nouvelle Java] _ Null-safe convient mieux ici pour spécifier de manière sélective ce qui implique et ce qui n'implique pas d'être initialisé d'être rapide après une erreur du programmeur.

    Q. Du code redondant peut être exécuté et des ressources inutiles peuvent être récupérées.
    UNE. Cela pourrait se produire si getPhotoByName() tenterait d'ouvrir une connexion à une base de données, créerait PreparedStatement et utiliserait enfin le nom de la personne comme paramètre SQL. L'approche pour une question inconnue donne une réponse inconnue (cas 1) fonctionne ici. Avant de récupérer des ressources, la méthode doit vérifier les paramètres et renvoyer un résultat "inconnu" si nécessaire.

    Q. Cette approche entraîne une pénalité de performance en raison de l’ouverture de la fermeture de l’essai.
    UNE. Les logiciels doivent être faciles à comprendre et à modifier en premier lieu. Ce n’est qu’après cela que l’on pourrait penser à la performance, et seulement au besoin! et en cas de besoin! ( source ), et beaucoup d’autres).

    PS Cette approche sera aussi raisonnable à utiliser que le principe : le code de traitement des erreurs distinct du code "normal" == est raisonnable à utiliser quelque part. Prenons l'exemple suivant:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }
    

    PPS. Pour ceux qui ont le moins de voix possible (et pas si vite pour lire la documentation), je voudrais dire que je n’ai jamais attrapé une exception de type pointeur nul (NPE) dans ma vie. Mais cette possibilité a été intentionnellement conçue par les créateurs Java, car NPE est une sous-classe de Exception. Nous avons un précédent dans l'histoire de Java lorsque ThreadDeath est un Error non pas parce que c'est en fait une erreur d'application, mais uniquement parce que cela n'était pas destiné à être intercepté! Combien de NPE convient pour être un Error que ThreadDeath! Mais ce n'est pas.

  3. Cochez 'No data' uniquement si la logique métier l'implique.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }
    

    et

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }
    

    Si appContext ou dataSource n'est pas initialisé, le runtime non géré NullPointerException va tuer le thread actuel et sera traité par Thread.defaultUncaughtExceptionHandler (pour que vous puissiez définir et utiliser votre enregistreur favori ou un autre mécanisme de notification). Si non défini, ThreadGroup # uncaughtException imprimera stacktrace à err err. Il faut surveiller le journal des erreurs d’application et ouvrir le problème Jira pour chaque exception non gérée qui est en fait une erreur d’application. Le programmeur devrait corriger un bogue quelque part dans l'initialisation.

68
Mykhaylo Adamovych

Java 7 a une nouvelle classe d’utilitaires Java.util.Objects sur laquelle il existe une méthode requireNonNull(). Cela ne fait que lancer une NullPointerException si son argument est null, mais cela nettoie un peu le code. Exemple:

Objects.requireNonNull(someObject);
someObject.doCalc();

Cette méthode est particulièrement utile pour vérifier juste avant une affectation dans un constructeur, où chaque utilisation de celle-ci peut économiser trois lignes de code:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

devient

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}
66
Stuart Marks

En fin de compte, le seul moyen de résoudre complètement ce problème consiste à utiliser un langage de programmation différent:

  • En Objective-C, vous pouvez faire l'équivalent d'appeler une méthode sur nil, et rien ne se passera absolument. Cela rend la plupart des vérifications nulles inutiles, mais cela peut rendre les erreurs beaucoup plus difficiles à diagnostiquer.
  • Dans Nice , un langage dérivé de Java, il existe deux versions de tous les types: une version potentiellement nulle et une version non nulle. Vous ne pouvez invoquer des méthodes que sur des types non nuls. Les types potentiellement nuls peuvent être convertis en types non-nuls grâce à une vérification explicite de null. Il est ainsi beaucoup plus facile de savoir où les vérifications nulles sont nécessaires et où elles ne le sont pas.
48
Michael Borgwardt

"Problème" commun en Java en effet.

Tout d'abord, mes pensées à ce sujet:

Je considère qu'il est mauvais de "manger" quelque chose quand NULL a été passé, où NULL n'est pas une valeur valide. Si vous ne quittez pas la méthode avec une sorte d'erreur, cela signifie que rien ne s'est mal passé dans votre méthode, ce qui n'est pas vrai. Ensuite, vous renvoyez probablement null dans ce cas, et dans la méthode de réception, vous recherchez à nouveau la valeur null, elle ne se termine jamais et vous obtenez "if! = Null", etc.

Ainsi, IMHO, null doit être une erreur critique empêchant toute exécution ultérieure (c'est-à-dire, où null n'est pas une valeur valide).

Voici comment je résous ce problème:

Tout d'abord, je suis cette convention:

  1. Toutes les méthodes publiques/API vérifient toujours ses arguments pour null
  2. Toutes les méthodes privées ne vérifient pas la valeur null car ce sont des méthodes contrôlées (laissez mourir avec l'exception nullpointer au cas où cela n'aurait pas été traité ci-dessus)
  3. Les seules autres méthodes qui ne vérifient pas la valeur null sont les méthodes utilitaires. Ils sont publics, mais si vous les appelez pour une raison quelconque, vous savez quels paramètres vous transmettez. C'est comme essayer de faire bouillir de l'eau dans la bouilloire sans fournir d'eau ...

Et enfin, dans le code, la première ligne de la méthode publique est la suivante:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

Notez que addParam () retourne self, ce qui vous permet d'ajouter plus de paramètres à vérifier.

La méthode validate() lancera une variable ValidationException si l'un des paramètres est null (cochée ou décochée est davantage un problème de conception/goût, mais ma ValidationException est cochée).

void validate() throws ValidationException;

Le message contiendra le texte suivant si, par exemple, "plans" est null:

" La valeur de l'argument non valide est null pour le paramètre [plans] "

Comme vous pouvez le constater, la deuxième valeur de la méthode addParam () (chaîne) est nécessaire pour le message de l'utilisateur, car vous ne pouvez pas facilement détecter le nom de la variable transmise, même avec réflexion (ce n'est pas l'objet de cet article ...).

Et oui, nous savons qu'au-delà de cette ligne, nous ne rencontrerons plus de valeur nulle. Nous invoquerons donc en toute sécurité des méthodes sur ces objets.

De cette façon, le code est propre, facile à gérer et lisible.

34
Oleg

Poser cette question indique que vous pouvez être intéressé par les stratégies de gestion des erreurs. L'architecte de votre équipe doit décider de la manière de traiter les erreurs. Il y a plusieurs moyens de le faire:

  1. autorisez les exceptions à se propager - attrapez-les à la "boucle principale" ou dans une autre routine de gestion.

    • vérifier les conditions d'erreur et les gérer correctement

Bien sûr, jetez également un coup d'œil à la programmation orientée aspect, elle aussi: elle dispose de moyens astucieux pour insérer if( o == null ) handleNull() dans votre code intermédiaire.

32
xtofl

En plus d'utiliser assert, vous pouvez utiliser les éléments suivants:

if (someobject == null) {
    // Handle null here then move on.
}

C'est légèrement mieux que:

if (someobject != null) {
    .....
    .....



    .....
}
32
fastcodejava

Juste n'utilisez jamais null. Ne le permets pas.

Dans mes classes, la plupart des champs et des variables locales ont des valeurs par défaut non null, et j'ajoute des instructions de contrat (des assertions permanentes) partout dans le code pour m'assurer que cela est appliqué (car il est plus succinct et plus expressif que de le laisser en tant que NPE et avoir ensuite à résoudre le numéro de ligne, etc.).

Une fois que j'ai adopté cette pratique, j'ai remarqué que les problèmes semblaient se résoudre d'eux-mêmes. Vous détecteriez des problèmes beaucoup plus tôt dans le processus de développement simplement par accident et vous vous rendriez compte que vous aviez un point faible… et plus important encore… cela aide à résumer les préoccupations de différents modules, différents modules pouvant se faire «confiance» les uns les autres, code avec if = null else construit!

Ceci est une programmation défensive et donne un code beaucoup plus propre à long terme. Toujours désinfecter les données, par exemple ici en appliquant des normes rigides, et les problèmes disparaissent.

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

Les contrats sont comme des tests en mini-unités qui sont toujours en cours, même en production, et quand les choses échouent, vous savez pourquoi, plutôt qu’un NPE aléatoire, vous devez en quelque sorte le découvrir.

30
ianpojman

Guava, une bibliothèque de base très utile de Google, dispose d'une API intéressante et utile pour éviter les valeurs NULL Je trouve UsingAndAvoidingNullExplained très utile.

Comme expliqué dans le wiki:

Optional<T> est un moyen de remplacer une référence T nullable par un valeur non nulle. Un facultatif peut contenir une référence T non nulle (auquel cas nous disons que la référence est "présente"), ou peut contenir rien (auquel cas nous disons que la référence est "absente"). Ce n'est jamais dit de "contenir null".

Usage:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
28
Murat Derya Özen

C'est un problème très courant pour tous les développeurs Java. Il existe donc un support officiel dans Java 8 pour résoudre ces problèmes sans code encombré.

Java 8 a introduit Java.util.Optional<T>. C'est un conteneur qui peut contenir ou non une valeur non nulle. Java 8 offre un moyen plus sûr de gérer un objet dont la valeur peut être nulle dans certains cas. Il est inspiré des idées de Haskell et Scala .

En un mot, la classe Optional inclut des méthodes pour traiter explicitement les cas où une valeur est présente ou absente. Cependant, l’avantage par rapport aux références null est que la classe Optional <T> vous oblige à penser au cas où la valeur n’est pas présente. En conséquence, vous pouvez empêcher les exceptions de pointeur null non souhaitées.

Dans l'exemple ci-dessus, nous avons une usine de service à domicile qui renvoie un descripteur à plusieurs appareils disponibles à la maison. Mais ces services peuvent ou non être disponibles/fonctionnels; cela signifie que cela peut entraîner une exception NullPointerException. Au lieu d’ajouter une condition null if avant d’utiliser un service, encapsulons-le dans Facultatif <Service>.

EMBALLAGE DE L'OPTION <T>

Considérons une méthode pour obtenir la référence d'un service d'une usine. Au lieu de renvoyer la référence de service, encapsulez-la avec facultatif. Cela permet à l'utilisateur de l'API de savoir que le service retourné peut ou non être disponible/fonctionnel, utiliser de manière défensive

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

Comme vous le voyez, Optional.ofNullable() fournit un moyen facile d’obtenir la référence encapsulée. Il existe un autre moyen d'obtenir la référence de Optional, soit Optional.empty() & Optional.of(). Un pour renvoyer un objet vide au lieu de réaccorder null et l'autre pour envelopper un objet non nullable, respectivement.

DONC, COMMENT EXACTEMENT-T-IL ÉVITER UNE VÉRIFICATION NULL?

Une fois que vous avez encapsulé un objet de référence, Optional fournit de nombreuses méthodes utiles pour appeler des méthodes sur une référence encapsulée sans NPE.

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent appelle le consommateur donné avec une référence s'il s'agit d'une valeur non nulle. Sinon, ça ne fait rien.

@FunctionalInterface
public interface Consumer<T>

Représente une opération qui accepte un seul argument d'entrée et ne renvoie aucun résultat. Contrairement à la plupart des autres interfaces fonctionnelles, Consumer est supposé fonctionner via des effets secondaires. Dans l'exemple de code ci-dessus, HomeService.switchOn(Service) est appelé si la référence de conservation facultative est non nulle.

Nous utilisons très souvent l'opérateur ternaire pour vérifier la condition NULL et renvoyer une valeur alternative ou une valeur par défaut. Facultatif fournit un autre moyen de gérer la même condition sans vérifier null. Optional.orElse (defaultObj) renvoie defaultObj si le type facultatif a une valeur null. Utilisons ceci dans notre exemple de code:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

Maintenant, HomeServices.get () fait la même chose, mais d'une meilleure façon. Il vérifie si le service est déjà initialisé ou non. Si c'est le cas, retournez-le ou créez un nouveau service. <T> .orElse (T) facultatif permet de renvoyer une valeur par défaut.

Enfin, voici notre code NPE et notre code sans vérification:

import Java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

Le message complet est NPE ainsi que le code sans chèque sans vérification….

21
Yogesh Devatraj

J'aime les articles de Nat Pryce. Voici les liens:

Dans les articles, il existe également un lien vers un référentiel Git pour un type Java Maybe que je trouve intéressant, mais je ne pense pas que cela seul puisse diminuer le fardeau de la vérification Après avoir effectué des recherches sur Internet, je pense que ! = Null pourrait être réduit principalement par une conception soignée.

20
Mr Palo

J'ai essayé le NullObjectPattern mais pour moi ce n'est pas toujours la meilleure façon de faire. Il y a parfois des cas où "aucune action" n'est pas appropriée.

NullPointerException est une exception Runtime qui signifie que c'est une faute des développeurs et avec suffisamment d'expérience, il vous dit exactement où se trouve l'erreur.

Maintenant à la réponse:

Essayez de rendre tous vos attributs et leurs accesseurs aussi privés que possible ou évitez de les exposer aux clients. Vous pouvez bien sûr avoir les valeurs d'argument dans le constructeur, mais en réduisant l'étendue, vous ne laissez pas la classe client transmettre une valeur non valide. Si vous devez modifier les valeurs, vous pouvez toujours créer une nouvelle object. Vous vérifiez les valeurs dans le constructeur uniquement une fois et dans le reste des méthodes, vous pouvez être presque sûr que les valeurs ne sont pas nulles.

Bien entendu, l'expérience est le meilleur moyen de comprendre et d'appliquer cette suggestion.

Octet!

18
OscarRyz

La meilleure alternative pour Java 8 ou une version plus récente consiste probablement à utiliser la classe Optional

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

Ceci est particulièrement utile pour les longues chaînes de valeurs null possibles. Exemple:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

Exemple sur la façon de lancer une exception sur null:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

Java 7 a introduit la méthode Objects.requireNonNull qui peut être utile lorsque quelque chose doit être vérifié pour déterminer s'il est non nul. Exemple:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();
15
Raghu K Nair

J'ignore fortement les réponses qui suggèrent d'utiliser les objets nuls dans chaque situation. Ce modèle peut rompre le contrat et enfouir les problèmes de plus en plus profond au lieu de les résoudre, sans mentionner que leur utilisation inappropriée créera une autre pile de code passe-partout qui nécessitera un entretien ultérieur.

En réalité, si quelque chose retourné par une méthode peut être nul et que le code appelant doit prendre une décision à ce sujet, il devrait y avoir un appel précédent qui assure l'état. 

N'oubliez pas non plus que ce modèle d'objet nul aura besoin de beaucoup de mémoire s'il est utilisé sans précaution. Pour cela, l'instance d'un NullObject doit être partagée entre les propriétaires et ne pas être une instance unigue pour chacun d'eux.

De plus, je ne recommanderais pas l'utilisation de ce modèle où le type est censé être une représentation de type primitif - comme les entités mathématiques, qui ne sont pas des scalaires: vecteurs, matrices, nombres complexes et objets POD (Plain Old Data), destinés à conserver l'état sous forme de types Java intégrés. Dans ce dernier cas, vous devriez appeler des méthodes getter avec des résultats arbitraires. Par exemple, que devrait renvoyer une méthode NullPerson.getName ()? 

Cela vaut la peine d’envisager de tels cas afin d’éviter des résultats absurdes.

14
spectre

Puis-je répondre plus généralement!

Nous habituellement sommes confrontés à ce problème lorsque les méthodes obtiennent les paramètres inattendus (le mauvais appel de méthode est la faute du programmeur). Par exemple: vous attendez un objet, vous obtenez plutôt un null. Vous vous attendez à obtenir une chaîne avec au moins un caractère, mais une chaîne vide ...

Donc, il n'y a pas de différence entre:

if(object == null){
   //you called my method badly!

}

ou

if(str.length() == 0){
   //you called my method badly again!
}

Ils veulent tous les deux s'assurer que nous avons reçu des paramètres valides avant de faire toute autre fonction.

Comme mentionné dans d'autres réponses, pour éviter les problèmes ci-dessus, vous pouvez suivre le modèle Design by contract. Veuillez consulter http://en.wikipedia.org/wiki/Design_by_contract

Pour implémenter ce modèle en Java, vous pouvez utiliser des annotations Java essentielles telles que javax.annotation.NotNull ou des bibliothèques plus sophistiquées telles que Hibernate Validator.

Juste un échantillon:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

Vous pouvez maintenant développer en toute sécurité la fonction principale de votre méthode sans avoir à vérifier les paramètres d'entrée, ils protègent vos méthodes des paramètres inattendus.

Vous pouvez aller plus loin et vous assurer que seuls des pojos valides peuvent être créés dans votre application. (échantillon du site du validateur Hibernate)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}
14
Alireza Fattahi
  1. Ne jamais initialiser les variables à null.
  2. Si (1) n'est pas possible, initialisez toutes les collections et tous les tableaux pour vider les collections/tableaux.

Faites cela dans votre propre code et vous pourrez éviter les contrôles! = Null.

La plupart du temps, les vérifications nulles semblent protéger les boucles sur les collections ou les tableaux, il suffit donc de les initialiser vides, vous n'aurez besoin d'aucune vérification nulle.

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

Il y a une petite surcharge en cela, mais cela en vaut la peine pour un code plus propre et moins NullPointerExceptions.

13
Stuart Axon

C'est l'erreur la plus commune survenue pour la plupart des développeurs.

Nous avons plusieurs façons de gérer cela.

Approche 1:

org.Apache.commons.lang.Validate //using Apache framework

notNull (objet Object, message String) 

Approche 2:

if(someObject!=null){ // simply checking against null
}

Approche 3:

@isNull @Nullable  // using annotation based validation

Approche 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}
13
Sireesh Yarlagadda
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}
10
tltester

Java 8 a introduit une nouvelle classe Optional dans le package Java.util.

Avantages de Java 8 Facultatif:

1.) Les contrôles nuls ne sont pas nécessaires.
2..) Plus aucune exception NullPointerException au moment de l'exécution.
3..) Nous pouvons développer des API propres et soignées. 

Facultatif - Objet conteneur pouvant contenir ou non une valeur non nulle. Si une valeur est présente, isPresent () retournera true et get () renverra la valeur.

Pour plus de détails, consultez la documentation Oracle: - https://docs.Oracle.com/javase/8/docs/api/Java/util/Optional.html

9
NeeruSingh

Vous pouvez utiliser FindBugs . Ils ont également un Eclipse plugin) qui vous aide à trouver des contrôles nuls en double (entre autres), mais gardez à l’esprit que vous devez parfois opter pour une programmation défensive. Il existe également Contrats pour Java qui peuvent être utiles.

8
Leen Toelen

Je suis les instructions ci-dessous pour éviter les contrôles nuls.

  1. Évitez autant que possible initialisation des variables membres. Initialise les variables dans la déclaration elle-même. Cela gérera NullPointerExceptions. 

  2. Décidez de mutability des variables membres au début du cycle. Utilisez des constructions de langage comme le mot clé final de manière efficace. 

  3. Si vous savez que les augmentations de méthode ne seront pas modifiées, déclarez-les en tant que final.

  4. Limitez autant que possible les mutation des données. Certaines variables peuvent être créées dans un constructeur et ne peuvent jamais être modifiées. Supprime les méthodes de définition publiques à moins qu'elles ne soient réellement requises.

    Par exemple. Supposons qu'une classe de votre application (A.Java) gère une collection telle que HashMap. Ne fournissez pas la méthode public getter dans A.Java et laissez B.Java ajouter directement un élément dans Map. A la place, fournissez une API dans A.Java, qui ajoute un élément à la collection. 

    // Avoid
    a.getMap().put(key,value)
    
    //recommended
    
    public void addElement(Object key, Object value){
           // Have null checks for both key and value here : single place
           map.put(key,value);
    }
    
  5. Et enfin, utilisez les blocs try{} catch{} finally{} aux bons endroits de manière efficace.

7
Ravindra babu

Depuis Java 7, la classe Java.util.Objects existe.

Mais depuis Java 8, vous pouvez utiliser les méthodes Objects.isNull(var) et Objects.nonNull(var) de la classe Objects pour effectuer la vérification du pointeur null.

Par exemple,

String var1 = null;
Date var2 = null;
Long var3 = null;

if(Objects.isNull(var1) && Objects.isNull(var2) && Objects.isNull(var3))
    System.out.println("All Null");
else if (Objects.nonNull(var1) && Objects.nonNull(var2) && Objects.nonNull(var3))
    System.out.println("All Not Null");
7
Philip John

Dans l'ensemble pour éviter la déclaration

if (object != null) {
    ....
}
  1. depuis Java 7, vous pouvez utiliser les méthodes Objects:

    Objects.isNull (objet)

    Objects.nonNull (objet)

    Objects.requireNonNull (objet)

    Objects.equals (object1, object2)

  2. depuis Java 8, vous pouvez utiliser la classe facultative ( quand utiliser

object.ifPresent(obj -> ...); Java 8

object.ifPresentOrElse(obj -> ..., () -> ...); Java 9

  1. utilisez la méthode contrat ( JSR 305 ) et utilisez Rechercher les bogues . Marquez votre code avec les annotations @javax.annotation.Nullable et @javax.annotation.Nonnnul. Des préconditions sont également disponibles.

    Preconditions.checkNotNull (objet);

  2. Dans des cas particuliers (par exemple pour Strings et Collections), vous pouvez utiliser les méthodes de l'utilitaire Apache-commons (ou Google guava):

public statique boolean isEmpty (CharSequence cs) // Apache CollectionUtils

public statique boolean isEmpty (Collection coll) // Apache StringUtils

public statique boolean isEmpty (Map map) // Apache MapUtils

public statique boolean isNullOrEmpty (@Nullable String string) // Guava Strings

  1. Lorsque vous devez attribuer une valeur par défaut lorsque null, utilisez Apache commons lang.

public static Object defaultIfNull (Objet Object, Object defaultValue)

6
fbokovikov

Une autre alternative:

La fonction simple suivante permet de masquer la vérification nulle (je ne sais pas pourquoi, mais je ne l'ai pas trouvée dans la même bibliothèque common):

public static <T> boolean isNull(T argument) {
    return (argument == null);
}

Vous pouvez maintenant écrire

if (!isNull(someobject)) {
    someobject.doCalc();
}

ce qui est à l’OMI un meilleur moyen d’exprimer != null.

6
jeha

Où que vous passiez un tableau ou un vecteur, initialisez-les à vide, au lieu de null. - De cette façon, vous éviterez de nombreuses vérifications nulles et tout va bien :)

public class NonNullThing {

   Vector vectorField = new Vector();

   int[] arrayField = new int[0];

   public NonNullThing() {

      // etc

   }

}
5
Stuart Axon

Je trouve que Guava Preconditions est très utile dans ce cas. Je n'aime pas laisser les valeurs null à l'exception de pointeur null car la seule façon de comprendre un NPE consiste à localiser le numéro de ligne. Les numéros de ligne dans la version de production et la version de développement peuvent être différents.

À l'aide de Guava Preconditions, je peux vérifier les paramètres null et définir un message d'exception significatif sur une ligne.

Par exemple,

Preconditions.checkNotNull(paramVal, "Method foo received null paramVal");
5
Gal Morad

Vous pouvez utiliser un intercepteur avant l'appel de la méthode. C'est ce sur quoi la programmation orientée aspect focus.

Supposons que M1 (Object test) soit une méthode et M2, une méthode dans laquelle nous appliquons un aspect avant un appel de méthode, M2(Object test2). Si test2 != null, appelez M1, sinon, faites autre chose. Cela fonctionne pour toutes les méthodes avec lesquelles vous voulez appliquer un aspect. Si vous souhaitez appliquer un aspect à un champ d'instance et à un constructeur, vous pouvez utiliser AspectJ . Spring peut également être le meilleur choix pour un aspect de méthode.

4
abishkar bhattarai

En Java 8, vous pouvez utiliser le type T pour variable-local/champ/argument-méthode/méthode-retour-type s'il n'a jamais affecté null (et ne pas rechercher null) ou taper Optional<T> s'il peut être null. Ensuite, utilisez la méthode map pour traiter T -> et la méthode flatMap pour traiter T -> Optional<R>:

class SomeService {
    @Inject
    private CompanyDao companyDao;

    // return Optional<String>
    public Optional<String> selectCeoCityByCompanyId0(int companyId) {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity);
    }

    // return String + default value
    public String selectCeoCityByCompanyId1(int companyId) {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity)
                .orElse("UNKNOWN");
    }

    // return String + exception
    public String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity)
                .orElseThrow(NoSuchElementException::new);
    }
}

interface CompanyDao {
    // real situation: no company for such id -> use Optional<Company> 
    Optional<Company> selectById(int id);
}

class Company {
    // company always has ceo -> use Person 
    Person ceo;
    public Person getCeo() {return ceo;}
}

class Person {
    // person always has name -> use String
    String firstName;
    // person can be without address -> use Optional<Address>
    Optional<Address> homeAddress = Optional.empty();

    public String getFirstName() {return firstName;}   
    public Optional<Address> getHomeAddress() {return homeAddress;}
}

class Address {
    //  address always contains country -> use String
    String country;
    //  city field is optional -> use Optional<String>
    Optional<String> city = Optional.empty();

    String getCountry() {return country;}    
    Optional<String> getCity() {return city;}
}
4
Ivan Golovach

Si vous utilisez Java8 ou une version ultérieure, optez pour la isNull(yourObject) à partir de Java.util.Objects.

Exemple:-

String myObject = null;

Objects.isNull(myObject); //will return true
3
Jobin Joseph

Java 8 a maintenant une classe facultative qui encapsule l'objet en considération et si une valeur est présente, isPresent () renverra true et get () renverra la valeur.

http://www.Oracle.com/technetwork/articles/Java/java8-optional-2175753.html

3
sidgate

Vous pouvez également utiliser Checker Framework (avec JDK 7 et versions ultérieures) pour vérifier de manière statique les valeurs NULL. Cela pourrait résoudre beaucoup de problèmes, mais nécessite l'exécution d'un outil supplémentaire qui ne fonctionne actuellement qu'avec OpenJDK AFAIK. https://checkerframework.org/

3
Jochen

Java 8 a introduit une nouvelle classe Optional dans le package Java.util. Il est utilisé pour représenter une valeur est présente ou absente. Le principal avantage de cette nouvelle construction réside dans le fait qu’il n’ya plus trop de vérifications de null et d’exceptions NullPointerException. Il évite toutes les exécutions NullPointerExceptions et nous aide à développer des API ou des applications propres et soignées Java. Comme les collections et les tableaux, il s'agit également d'un conteneur pouvant contenir au plus une valeur.

Ci-dessous quelques liens utiles que vous pouvez suivre

https://www.mkyong.com/Java8/Java-8-optional-in-depth/

https://dzone.com/articles/Java-8-optional-avoid-null-and

3
rohit prakash

D'accord, j'ai maintenant répondu techniquement à des millions de fois, mais je dois dire ceci car il s'agit d'une discussion sans fin avec des programmeurs Java.

Désolé mais je ne suis pas d'accord avec presque tout ce qui précède. La raison pour laquelle nous devons tester null en Java est que les programmeurs Java ne doivent pas savoir gérer la mémoire. 

Je dis cela parce que j'ai une longue expérience de la programmation en C++ et que nous ne le faisons pas. En d’autres termes, vous n’avez pas besoin de le faire. Et notez qu'en Java, si vous cliquez sur un pointeur suspendu, vous obtenez une exception normale. en C++, cette exception n'est normalement pas interceptée et termine le programme.

Vous ne voulez pas faire ça? Suivez ensuite quelques règles simples en C/C++.

N’instanciez pas les choses si facilement, pensez que chaque "nouveau" peut vous causer beaucoup de problèmes et SUIVRE ces règles simples.

Une classe ne doit accéder à la mémoire que de trois manières différentes ->

  1. Il peut "avoir" les membres de la classe, et ils vont suivre ces règles:

    1. TOUS les membres "HAS" sont créés "new" dans le constructeur.
    2. Vous allez fermer/allouer dans destructor ou une fonction close () Équivalente en Java pour la même classe et AUCUN autre.

Cela signifie que vous devez avoir à l'esprit (comme le fait Java) qui est le propriétaire ou le parent de chaque ressource et respecter cette propriété. Un objet est uniquement supprimé par la classe qui l'a créé. Aussi ->

  1. Certains membres seront "UTILISÉS" mais ne seront ni propriétaires ni "HAVE". Ce sont "OWN" dans une autre classe et transmis en tant qu'arguments au constructeur. Comme ceux-ci appartiennent à une autre classe, nous ne supprimerons ni ne fermerons jamais cette propriété, seul le parent peut le faire.

  2. Une méthode dans une classe peut également instancier des objets locaux pour une utilisation interne qui ne s'échappera JAMAIS du côté de la classe, ou ils auraient dû être des objets "a" normaux.

Enfin, pour que tout cela fonctionne, vous devez avoir une conception disciplinée avec des classes sous forme de hiérarchie et ne faisant aucun cycle.

Sous cette conception, ET suivant les règles ci-dessus, il n’ya aucun moyen pour une classe enfant d’une conception hiérarchique d’accéder à un pointeur détruit, car cela signifie qu’un parent a été détruit avant un enfant, ce que la conception acyclique hiérarchique permettez-ceci.

Enfin, rappelez-vous également que, lors du démarrage de votre système, vous devez créer de haut en bas de la hiérarchie et détruire de bas en haut. Vous n'aurez jamais un pointeur nul, ou quelqu'un enfreint les règles.

2
Alex Vaz

La façon d'éviter null-checks inutile est simple à énoncer:

You need to know which variables can be null, and which cannot, and you need to be confident about which category a given variable fall into.

Mais, même s’il est assez simple de le dire, il est plus difficile de le réaliser. La clé réside dans la partie confident, car comment être sûr qu'une variable ne peut pas être nulle?

Il n’existe pas de solution miracle à ce problème, mais voici quelques conseils:

  1. Code propre. La chose la plus importante pour pouvoir raisonner sur le comportement d’un morceau de code est qu’il soit écrit dans un sujet facile à comprendre. Nommez vos variables en fonction de ce qu'elles représentent, nommez vos méthodes, appliquez le Single responsibility principle (le S dans SOLID: http://en.wikipedia.org/wiki/SOLID_(object-oriented_design) , it signifie que chaque morceau de code devrait avoir une responsabilité unique et faire ceci et rien d’autre). Une fois que votre code est propre, il est beaucoup plus facile de le raisonner, également sur plusieurs niveaux/couches de code. Avec du code en désordre, essayer de comprendre ce qu’est une méthode peut vous faire oublier pourquoi vous lisez la méthode en premier lieu. (Astuce: lisez "Clean Code" de Robert C. Martin)

  2. Évitez de renvoyer les valeurs null. Si une valeur null empêche votre programme de fonctionner correctement, lancez plutôt une exception (assurez-vous d'ajouter le traitement d'erreur approprié.) Les cas dans lesquels le renvoi d'une valeur null peut être acceptable consistent, par exemple, à extraire un objet de la base de données. Dans ces cas, écrivez un code qui gère les valeurs null et notez derrière votre oreille que nous avons ici quelque chose qui pourrait renvoyer null. Handle a renvoyé des valeurs null aussi proches que possible de l'appelant de la méthode renvoyant null (ne le renvoyez pas simplement aveuglément dans la chaîne d'appels.)

  3. Ne transmettez jamais JAMAIS des valeurs null explicites en tant que paramètres (du moins pas pour toutes les classes). Si vous êtes dans une position où la transmission d'un paramètre null- est la seule option possible, la création d'une nouvelle méthode ne disposant pas de ce paramètre est la voie à suivre. 

  4. Validez votre entrée! Identifiez les "points d'entrée" de votre application. Ils peuvent tout: services Web, services REST, classes d'EJB distantes, contrôleurs, etc. Pour chaque méthode de ces points d'entrée, demandez-vous: "Cette méthode sera-t-elle correctement exécutée si ce paramètre est null?" Si la réponse est non, ajoutez Validate.notNull(someParam, "Can't function when someParam is null!");. Cela lancera une IllegalArgumentException si le paramètre requis est manquant. La bonne chose à propos de ce type de validation dans les points d’entrée, c’est que vous pouvez alors facilement supposer, dans le code exécuté depuis le point d’entrée, que cette variable ne sera jamais nulle! De plus, si cela échoue, le débogage étant au point d'entrée, il est beaucoup plus facile que si vous veniez de recevoir une NullPointerException au plus profond de votre code, puisqu'un tel échec ne peut signifier qu'une chose: le client n'a pas vous envoyer toutes les informations requises. Dans la plupart des cas, vous souhaitez valider tous les paramètres d'entrée. Si vous vous retrouvez dans une position où vous devez autoriser un grand nombre de valeurs null-, cela peut être le signe d'une interface mal conçue, nécessitant une refactorisation/des ajouts pour répondre aux besoins. des clients.

  5. Lorsque vous travaillez avec Collections, retournez un vide plutôt que null! 

  6. Lorsque vous travaillez avec une base de données, utilisez les contraintes not null-. De cette façon, vous saurez qu'une valeur lue dans la base de données ne peut pas être nulle et vous n'avez pas à la vérifier.

  7. Structurez votre code et respectez-le. Cela vous permet de faire des hypothèses sur le comportement du code. Par exemple, si toutes les entrées de votre application sont validées, vous pouvez supposer que ces valeurs ne seront jamais nulles. 

  8. Si vous ne le faites pas déjà, écrivez des tests automatisés de votre code. En écrivant des tests, vous allez raisonner à propos de votre code et vous serez également plus confiant dans le fait qu'il fait ce qu'il est censé faire. De plus, des tests automatisés vous protègent des erreurs lors du refactoring, en vous faisant savoir immédiatement que ce morceau de code ne fait plus ce qu'il était.

Vous devez toujours effectuer une vérification nulle bien sûr, mais cela peut être réduit au strict minimum (c'est-à-dire la situation où know est susceptible de générer une valeur nulle, au lieu d'être partout, juste pour être sûr.) pour annuler les chèques, je préfère en réalité utiliser l'opérateur ternaire (mais utilisez-le avec précaution, lorsque vous commencez à les imbriquer, ils sont vraiment compliqués.)

public String nullSafeToString(final Object o) {
    return o != null ? o.toString() : "null";
}
2
Tobb

Tout d'abord, nous ne pouvons pas vraiment supprimer toutes les conditions nulles. Nous pouvons les réduire en utilisant les annotations @NotNull et @Nullable (comme déjà mentionné). Mais cela doit être soutenu par un cadre. C'est là que Oval peut aider.

L'idée de base est que l'objet/les paramètres/le constructeur doivent toujours satisfaire les conditions préalables. Vous pouvez avoir beaucoup de conditions préalables telles que Nullable, NotNull et OVal veillera à ce qu'un objet soit dans un état cohérent lorsqu'il est appelé.

Je suppose que OVal utilise en interne AspectJ pour valider les conditions préalables.

@Guarded
public class BusinessObject
{
  public BusinessObject(@NotNull String name)
  {
    this.name = name;
  }

  ...
}

Par exemple,

// Throws a ConstraintsViolatedException because parameter name is null
BusinessObject bo = new BusinessObject(null);
2
Vinay Lodha

Nous utilisons les bibliothèques Apache (Apache Commons) pour ce numéro.

ObjectUtils.equals(object, null)

ou

CollectionUtils.isEmpty(myCollection);

ou 

StringUtils.isEmpty("string");

J'aime la réponse précédente avant, comme pratique, de fournir des valeurs par défaut initiales ou des ensembles vides pour les collections afin de minimiser le besoin.

Celles-ci peuvent être des utilisations simples qui vous empêchent d’avoir NullPointerException ou d’utiliser une collection vide. Cela ne répond pas à la question de savoir quoi faire avec l'objet null, mais ceux-ci fournissent des vérifications pour les validations de base de l'objet ou de la collection. 

J'espère que cela t'aides. 

1
iowatiger08

Je préfère ça

public void simpleFunc(SomeObject someObject){
    someObject = someObject != null ? someObject : new SomeObject(null);
    someObject.doSomething();
}

Bien sûr, dans mon exemple, SomeObject gère gracieusement un paramètre null. Par exemple, enregistrer un tel événement et ne plus rien faire.

1
drzymala

Avec Java 8, vous pouvez passer un fournisseur à une méthode d’aide comme ci-dessous,

if(CommonUtil.resolve(()-> a.b().c()).isPresent()) {

}

Ci-dessus remplace le code de plaque de chaudière comme ci-dessous,

if(a!=null && a.b()!=null && a.b().c()!=null) {

}

//CommonUtil.Java

 public static <T> Optional<T> resolve(Supplier<T> resolver) {
        try {
            T result = resolver.get();
            return Optional.ofNullable(result);
        } catch (NullPointerException var2) {
            return Optional.empty();
        }
    }
1
nilesh

Il est possible de définir des méthodes util qui traitent les vérifications de nullité imbriquées de manière presque jolie avec Java 8 lambdas.

void example() {
    Entry entry = new Entry();
    // This is the same as H-MANs solution 
    Person person = getNullsafe(entry, e -> e.getPerson());    
    // Get object in several steps
    String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
    // Call void methods
    doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());        
}

/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
    if (o1 != null) return f1.apply(o1);
    return null; 
}

public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
    return getNullsafe(getNullsafe(o0, f1), f2);
}

public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
    return getNullsafe(getNullsafe(o0, f1, f2), f3);
}


/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
    if (o1 != null) f1.accept(o1);
}

public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
    doNullsafe(getNullsafe(o0, f1), f2);
}

public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
    doNullsafe(getNullsafe(o0, f1, f2), f3);
}


class Entry {
    Person getPerson() { return null; }
}

class Person {
    Name getName() { return null; }
}

class Name {
    void nameIt() {}
    String getGivenName() { return null; }
}

(Cette réponse a été publiée pour la première fois ici .)

1
Lii

Kotlin avec la sécurité nulle est une alternative élégante, mais cela signifie un plus grand changement.

0
Francis

Pour les classes d’utilitaires, vous pouvez vérifier que les paramètres ne sont pas nuls.

Dans tous les autres cas, il se peut que vous n'ayez pas à le faire. Utilisez autant que possible l’encapsulation afin de réduire les endroits où vous êtes tenté de rechercher null.

0
daniel

Vous pouvez coupler votre classe à des tests unitaires à l'aide d'un framework tel que JUnit . Ainsi, votre code sera propre (aucune vérification inutile) et vous serez assuré que vos instances ne seront pas nulles.

C’est une bonne raison (parmi d’autres) d’utiliser les tests unitaires.

0
Mehdi

Un modèle d'objet nul peut être utilisé comme solution à ce problème. Pour cela, la classe de someObject doit être modifiée. 

public abstract class SomeObject {
   public abstract boolean isNil();
}

public class NullObject extends SomeObject {
   @Override
   public boolean isNil() {
      return true;
   }
}
public class RealObject extends SomeObject {
   @Override
   public boolean isNil() {
      return false;
   }
}

Maintenant, au lieu de vérifier,

 if (someobject != null) {
    someobject.doCalc();
}

On peut utiliser,

if (!someObject.isNil()) {
   someobject.doCalc();
}

Référence: https://www.tutorialspoint.com/design_pattern/null_object_pattern.htm

0
Vidura Mudalige

Une option que vous avez

  • Utilisez les @RequiresNonNull de checker framework sur les méthodes. par exemple, vous obtenez ceci si vous appelez une méthode annotée comme telle, avec un argument nul. Cela échouera pendant la compilation, même avant que votre code ne soit exécuté! car au moment de l'exécution ce sera NullPointerException

    @RequiresNonNull(value = { "#1" })
    static void check( Boolean x) {
        if (x) System.out.println("true");
        else System.out.println("false");
    }
    
    public static void main(String[] args) {
    
    
        check(null);
    
    }
    

obtient 

[ERROR] found   : null
[ERROR] required: @Initialized @NonNull Boolean
[ERROR] -> [Help 1]

Il existe d'autres méthodes telles que l'option Utiliser Java 8 facultatif, les annotations goyaves, le modèle d'objet nul, etc.

0
Binod Pant

Une autre alternative au contrôle! = Null est (si vous ne pouvez pas vous en débarrasser du point de vue du design):

Optional.ofNullable(someobject).ifPresent(someobject -> someobject.doCalc());

ou

Optional.ofNullable(someobject).ifPresent(SomeClass::doCalc);

SomeClass étant le type de someobject.

Cependant, vous ne pouvez pas obtenir une valeur de retour de doCalc (), donc utile uniquement pour les méthodes void.

0
Sebastian Brandt

Une approche fonctionnelle peut aider à encapsuler les vérifications nulles répétitives et à exécuter du code anonyme comme dans l'exemple ci-dessous.

    BiConsumer<Object, Consumer<Object>> consumeIfPresent  = (s,f) ->{
        if(s!=null) {
            f.accept(s);
        }
    };

    consumeIfPresent.accept(null, (s)-> System.out.println(s) );
    consumeIfPresent.accept("test", (s)-> System.out.println(s));

    BiFunction<Object, Function<Object,Object>,Object> executeIfPresent  = (a,b) ->{
        if(a!=null) {
            return b.apply(a);
        }
        return null;
    };
    executeIfPresent.apply(null, (s)-> {System.out.println(s);return s;} );
    executeIfPresent.apply("test", (s)-> {System.out.println(s);return s;} );
0
Ramprabhu