java test Éviter!=Déclarations nulles




nullpointerexception processing (20)

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

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

Si des valeurs non définies sont autorisées:

Si vous souhaitez définir une nouvelle API dans laquelle des valeurs non définies ont un sens , utilisez le modèle d'option (qui 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".
  • L'option est une monade , il n'y a donc pas besoin de vérification verbale des valeurs nulles, utilisez simplement map / foreach / getOrElse ou un combinateur similaire pour utiliser la valeur en toute sécurité (example) .

Java 8 a une classe Optional intégrée (recommandée); pour les versions antérieures, il existe des alternatives de bibliothèque, par exemple, Optional ou Guava , Option . Mais comme beaucoup de modèles de styles fonctionnels, l’option Option en Java (même 8) donne un résultat assez sophistiqué, que vous pouvez réduire à l’aide d’un langage JVM moins détaillé, par exemple Scala ou Xtend.

Si vous devez utiliser une API pouvant renvoyer des valeurs NULL , vous ne pouvez pas faire grand-chose en Java. Xtend et Groovy ont l' opérateur Elvis ?: Et l' opérateur de déréférence null-safe ?. , mais notez que ceci retourne null dans le cas d’une référence null, donc il "diffère" le traitement approprié de null.

https://code.i-harness.com

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://stackoverflow.com/a/2386013/12943 pour une approche plus récente.


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 cet object n'est pas nul.

S'il s'agit d'une méthode interne (ne faisant pas partie d'une API), indiquez simplement qu'elle ne peut pas être null, 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 je 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 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 sera peut-être plus facile de vous donner des exemples si vous montrez des exemples d'utilisation typique de cet idiome.


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 .


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


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.


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

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

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.


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


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.

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


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



    .....
}

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!


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

Dans les articles, il y a é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 réduire le fardeau de vérification du code. Après avoir fait des recherches sur Internet, je pense que ! = Le code vide peut être réduit principalement par une conception soignée.


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

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

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.


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




null