Java Language Piège - "Réussir" des nulls inattendus


Exemple

Sur StackOverflow, nous voyons souvent du code comme celui-ci dans Réponses:

public String joinStrings(String a, String b) {
    if (a == null) {
        a = "";
    }
    if (b == null) {
        b = "";
    }
    return a + ": " + b;
}

Souvent, cela est accompagné d'une assertion qui est la "meilleure pratique" pour tester null comme ceci pour éviter NullPointerException .

Est-ce la meilleure pratique? En bref: non

Certaines hypothèses sous-jacentes doivent être remises en question avant de pouvoir dire si c'est une bonne idée de le faire dans nos joinStrings :

Qu'est-ce que cela signifie pour que "a" ou "b" soit nul?

Une valeur de String peut être zéro ou plusieurs caractères, nous avons donc déjà un moyen de représenter une chaîne vide. Est-ce que null signifie quelque chose de différent de "" ? Si non, il est alors problématique d'avoir deux manières de représenter une chaîne vide.

Est-ce que le null provient d'une variable non initialisée?

Un null peut provenir d'un champ non initialisé ou d'un élément de tableau non initialisé. La valeur peut être non initialisée par conception ou par accident. Si c'était par accident, alors c'est un bug.

Le null représente-t-il un "ne sait pas" ou une "valeur manquante"?

Parfois, un null peut avoir un sens véritable; Par exemple, la valeur réelle d'une variable est inconnue ou indisponible ou "facultative". Dans Java 8, la classe Optional offre un meilleur moyen d’exprimer cela.

S'il s'agit d'un bogue (ou d'une erreur de conception), faut-il "réparer"?

Une interprétation du code est que nous "réparons" un null inattendu en utilisant une chaîne vide à sa place. La stratégie est-elle correcte? Serait-il préférable de laisser l'exception NullPointerException se produire, puis d'attraper l'exception plus haut dans la pile et de l'enregistrer en tant que bogue?

Le problème avec "rendre bon" est que cela risque de cacher le problème ou de rendre le diagnostic plus difficile.

Est-ce efficace / bon pour la qualité du code?

Si l'approche "make good" est utilisée de manière cohérente, votre code contiendra beaucoup de tests null "défensifs". Cela va le rendre plus long et plus difficile à lire. En outre, tous ces tests et «correctifs» sont susceptibles d’avoir un impact sur les performances de votre application.

En résumé

Si null est une valeur significative, alors le test du cas null est la bonne approche. Le corollaire est que si une valeur null est significative, cela devrait être clairement documenté dans les javadocs de toutes les méthodes qui acceptent la valeur null ou la renvoient.

Sinon, il est préférable de traiter un null inattendu en tant qu'erreur de programmation et de laisser le NullPointerException se produire pour que le développeur sache qu'il y a un problème dans le code.