java pointer - Éviter!=Déclarations nulles




exception if (25)

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.

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.


La meilleure alternative pour Java 8 ou plus récent est probablement d'utiliser la Optionalclasse.

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 Objects.requireNonNullméthode qui peut être utile lorsque quelque chose doit être vérifié pour la non-nullité. Exemple:

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

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

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.

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.


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;

   // ...
}

Avec Java 8, la nouvelle classe java.util.Optional apporte une solution au 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 un exemple de fruit donné:

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 être 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 propose d'autres méthodes pratiques, telles que orElse qui permettent d'utiliser une valeur par défaut, et ifPresent qui fonctionne avec les 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 null) ainsi que la solution (partielle) apportée par Optional sont bien expliquées: Objets facultatifs Java .


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

Null n'est pas un "problème". Il fait partie intégrante d’un ensemble complete outils de modélisation. Le logiciel vise à modéliser la complexité du monde et à supporter son fardeau. Null indique "Pas de données" ou "Inconnu" en Java, etc. 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 retournerai null. Une alternative serait de lancer une exception significative pour indiquer un problème qui ne peut pas être (ou ne pasne voulez pas être) résolus sur-le-champ et déléguez-le 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 lorsque cela est correct du point de vue commercial) Le fait de vérifier les arguments null une fois dans une méthode avant l'utilisation évite à 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 (regard vers 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. C’est un cas plutôt théorique et dans la plupart des cas, vous devriez préférer une API java null safe (au cas où elle sera publiée dans 10 ans), mais il NullPointerExceptions’agit d’une sous-classe d’un fichier Exception. Il s’agit donc d’une forme Throwablequi indique les conditions qu’une application raisonnable pourrait vouloir saisir ( 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, de le détecter NullPointerException.

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

    Des questions pourraient se poser:

    Q. Que faire si getPhotoDataSource()retourne null?
    A. 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). La nouvelle API Java Null-safe s’adapte mieux ici pour spécifier de manière sélective ce qui implique et ce qui n’implique pas d’être initialisé pour éviter les erreurs de programmation.

    Q. Du code redondant peut être exécuté et des ressources inutiles peuvent être récupérées.
    A. Cela pourrait se produire si vous getPhotoByName()vouliez ouvrir une connexion de base de données, créer PreparedStatementet utiliser 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.
    A. Le logiciel doit être facile à 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 si nécessaire! ( source ) et beaucoup d’autres).

    PSCette approche sera aussi raisonnable à utiliser que le code de traitement des erreurs séparé du principe de code "normal" est raisonnable à utiliser dans certains endroits. 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é d'exception de pointeur nul (NPE) dans ma vie. Mais cette possibilité a été intentionnellement conçue par les créateurs de Java, car NPE est une sous-classe de Exception. Nous avons un précédent dans l’histoire de Java quand ce ThreadDeathn’est Errorpas parce qu’il s’agit d’une erreur d’application, mais uniquement parce que cela n’a pas été prévu! Combien de NPE convient pour être un Errorque ThreadDeath! Mais ce n'est pas.

  3. Recherchez «Pas de données» 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 supprimera le thread actuel et sera traité par Thread.defaultUncaughtExceptionHandler (pour que vous définissiez et Thread.defaultUncaughtExceptionHandler votre enregistreur favori ou un autre Thread.defaultUncaughtExceptionHandler notification). S'il n'est pas défini, ThreadGroup#uncaughtException uncaughtException imprimera stacktrace avec une erreur système. 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.


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


  • 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 nuls, dites-le dans le fichier javadoc et utilisez une assertion.

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

Il existe une proposition pour ajouter de nouvelles annotations dans Java7 afin d’aider les paramètres null / notnull: http://tech.puredanger.com/java7/#jsr308


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!


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");
}

Guava, une bibliothèque de base très utile de Google, possède une API intéressante et utile pour éviter les valeurs nulles. Je trouve Guava très utile.

Comme expliqué dans le wiki:

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

Usage:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

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.


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;
}

"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 lorsque 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 () renvoie self, ce qui vous permet d'ajouter plus de paramètres à vérifier.

La méthode validate()jettera coché ValidationExceptionsi l'un des paramètres est nul (coché ou décoché, c'est plutôt un problème de conception / goût, mais ma ValidationExceptionest coché).

void validate() throws ValidationException;

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

" La valeur de l'argument non valide est nulle 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 le cas de l'objet de cette publication ...).

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.


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.


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 .


En plus d'utiliser, assertvous 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) {
    .....
    .....



    .....
}

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


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 à rechercher 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 déclarations d' 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 la sortie de la méthode toString() sera incluse 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 -ea . 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.

Cependant, si c'est le code que vous contrôlez (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 la valeur 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 d'objet Null :

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 une conception bien meilleure car elle 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 à la saisie 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 moche, 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);
        }
    }
}

Vous en faites un peu trop. Pour vérifier si une variable n'a pas de valeur, il suffit de vérifier par rapport à undefined et à null.

function isEmpty(value){
    return (typeof value === "undefined" || value === null);
}

Cela suppose 0 , "" , et les objets (même l'objet vide et le tableau) sont des "valeurs" valides.





java object nullpointerexception null