java pointer exception - Éviter! = Déclarations nulles



15 Answers

Si vous utilisez (ou prévoyez d’utiliser) un environnement de développement Java tel que JetBrains IntelliJ IDEA , Eclipse ou Netbeans ou un outil tel que 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, car la fonction helloWorld() ne renverra jamais la valeur 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 un bon moyen 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 les @Nullable @NotNull , ils ont ajouté la prise en charge de toute autre @Nullable @NotNull .

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

if test nullpointerexception

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 , lorsqu'il est inconnu si l'objet est null ou non.

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




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 NullObject pattern peut-être savoir qu'il existe une proposition sur la table pour Java 7 d'ajouter "null -safe handling " - 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();  
}  

Le ?. signifie que référence à l'identifiant de gauche uniquement s'il n'est pas null, sinon évaluer le reste de l'expression comme null . Certaines personnes, comme Dick Wall, membre de Java Posse, et les électeurs de Devoxx aiment vraiment cette proposition, mais il y a également une opposition, car elle encouragera davantage l'utilisation de null comme valeur sentinelle.

Mise à jour: une proposed d'un opérateur null-safe en Java 7 a été soumise dans le cadre du projet Coin. La syntaxe est un peu différente de l'exemple ci-dessus, mais c'est 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.




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") ) {
 // ...
}

donnera lieu à une NullPointerException si foo n'existe pas.

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

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



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

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 par null dans 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");



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 quant à ce que votre code devrait faire dans ce cas ... Par exemple, il ne devrait jamais être nul, ignorez-le et laissez une exception NullPointerException être levée. Le code d'appel donnera tout autant le sens d'un NPE qu'un exception 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.




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); .




Java 7 a une nouvelle java.util.Objectsclasse d’utilitaires sur laquelle il existe une requireNonNull()méthode. Cela ne fait que jeter un NullPointerExceptionsi son argument est nul, mais cela nettoie un peu le code. Exemple:

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

Cette méthode est particulièrement utile pour checking juste avant une affectation dans un constructeur, où chaque utilisation peut enregistrer 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");
}



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 nil, mais rien ne se passera. 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 via une vérification explicite de null. Cela rend beaucoup plus facile de savoir où les vérifications nulles sont nécessaires et où elles ne le sont pas.



Poser cette question indique que vous pouvez être intéressé par les stratégies de traitement 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 propose des méthodes pratiques pour insérer if( o == null ) handleNull()dans votre code-octet.




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 des if = null elseconstructions!

Ceci est une programmation défensive et donne un code beaucoup plus propre à long terme. Assainissez toujours les données, par exemple ici en appliquant des normes strictes, et les problèmes disparaîtront.

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 comprendre.




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 s'inspire des idées de Haskell et de 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 ifcondition null avant d'utiliser un service, encapsulons-la dans <Service> facultatif.

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. Il indique à l'utilisateur de l'API 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, il Optional.ofNullable()existe un moyen simple d’envelopper la référence. Il existe un autre moyen d’obtenir la référence à 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 devrait fonctionner via des effets secondaires. C'est tellement propre et facile à comprendre. Dans l'exemple de code ci-dessus, HomeService.switchOn(Service)est invoqué si la référence de possession facultative est non nulle.

Nous utilisons très souvent l'opérateur ternaire pour vérifier la condition nulle 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 post complet est à la fois NPE et Null Check-Free Code… Vraiment? .




J'ai essayé le NullObjectPatternmais 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.

NullPointerExceptionest une exception d'exécution qui signifie que c'est la 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 en créer un nouveau object. Vous vérifiez les valeurs dans le constructeur une seule 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!




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

Nous sommes généralement confrontés à ce problème lorsque les méthodes obtiennent les paramètres d’une manière inattendue (le mauvais appel de méthode est la faute du programmeur). Par exemple: vous vous attendez à obtenir un objet, vous obtenez plutôt un null. Vous vous attendez à obtenir une chaîne avec au moins un caractère, à la place, vous obtenez 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 Conception par contrat . Veuillez consulter http://en.wikipedia.org/wiki/Design_by_contract .

Pour implémenter ce modèle en java, vous pouvez utiliser des annotations java principales, 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 de validation en veille prolongée)

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}



  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.




public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}



Related