J'utilise x != null
pour éviter NullPointerException
. Y a-t-il une alternative?
if (x != null) {
// ...
}
J'utilise x != null
pour éviter NullPointerException
. Y a-t-il une alternative?
if (x != null) {
// ...
}
Cela me semble être un problème assez courant que les développeurs juniors à intermédiaires ont tendance à rencontrer à un moment donné : ils ne connaissent pas ou ne font pas confiance aux contrats auxquels ils participent et vérifient défensivement les nulls. De plus, lorsqu'ils écrivent leur propre code, ils ont tendance à renvoyer des nulls pour indiquer quelque chose nécessitant ainsi à l'appelant de vérifier les nulls.
Pour le dire autrement, il y a deux cas où la vérification de null se pose :
Où null est une réponse valide en termes de contrat; et
Où ce n'est pas une réponse valide.
(2) est facile. À partir de Java 1.7, vous pouvez utiliser Objects.requireNonNull(foo)
. (Si vous êtes coincé avec une version précédente, alors les assert
tions peuvent être une bonne alternative.)
L'utilisation "correcte" de cette méthode serait comme ci-dessous. La méthode renvoie l'objet passé en elle et lance une NullPointerException
si l'objet est null. Cela signifie que la valeur retournée est toujours non nulle. La méthode est principalement destinée à valider les paramètres.
public Foo(Bar bar) {
this.bar = Objects.requireNonNull(bar);
}
Elle peut également être utilisée comme une assert
ion puisqu'elle lance une exception si l'objet est null. Dans les deux utilisations, un message peut être ajouté qui sera affiché dans l'exception. Ci-dessous, on l'utilise comme une assertion et en fournissant un message.
Objects.requireNonNull(someobject, "si someobject est nul alors quelque chose ne va pas");
someobject.doCalc();
En général, lancer une exception spécifique comme NullPointerException
lorsque la valeur est null mais ne devrait pas l'être est favorable à lancer une exception plus générale comme AssertionError
. C'est l'approche mise en œuvre par la bibliothèque Java ; préférant NullPointerException
à IllegalArgumentException
lorsque l'argument ne peut pas être null.
(1) est un peu plus compliqué. Si vous n'avez aucun contrôle sur le code que vous appelez, alors vous êtes coincé. Si null est une réponse valide, vous devez vérifier sa présence.
S'il s'agit du code que vous contrôlez, cependant (ce qui est souvent le cas), c'est une autre histoire. Évitez d'utiliser les nulls comme réponse. Avec les méthodes qui renvoient des collections, c'est facile : renvoyez des collections vides (ou des tableaux) au lieu des nulls la plupart du temps.
Avec les non-collections, cela peut ê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 en ligne de commande pour quelque chose. Vous pourriez faire le contrat qu'il renvoie null s'il n'y a pas d'action appropriée. Cela conduit à la vérification de null dont vous parlez.
Une solution alternative est de ne jamais renvoyer null et d'utiliser plutôt le modèle d'objet nul:
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* ne rien faire */ }
};
public Action findAction(String userInput) {
// ...
if ( /* nous ne pouvons trouver aucune action */ ) {
return DO_NOTHING;
}
}
}
Comparez :
Parser parser = ParserFactory.getParser();
if (parser == null) {
// et maintenant ?
// ceci serait un exemple où null n'est pas (ou ne devrait pas être) une réponse valide
}
Action action = parser.findAction(someInput);
if (action == null) {
// ne rien faire
} else {
action.doSomething();
}
à
ParserFactory.getParser().findAction(someInput).doSomething();
ce qui est un bien meilleur design car il conduit à un code plus concis.
Cela dit, il est peut-être tout à fait approprié que la méthode findAction() lance une Exception avec un message d'erreur significatif -- surtout dans ce cas où vous vous fiez à l'entrée utilisateur. Ce serait beaucoup mieux pour la méthode findAction de lancer une Exception que pour la méthode appelante de s'arrêter avec une simple NullPointerException sans explication.
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
Ou si vous trouvez le mécanisme try/catch trop laid, au lieu de Ne Rien Faire, votre action par défaut devrait fournir un retour d'information à l'utilisateur.
public Action findAction(final String userInput) {
/* Code pour renvoyer l'Action demandée si trouvée */
return new Action() {
public void doSomething() {
userConsole.err("Action non trouvée : " + userInput);
}
}
}
Bonne réponse, en particulier en mentionnant les assertions. Je viens de C et je les utilise constamment. En ce qui concerne les objets Null, ce ne sont PAS une solution miracle. J'ai souvent passé des heures à déboguer du code qui s'est avéré être un objet Null utilisé, ne faisant rien (ou retournant ses valeurs par défaut) alors qu'une NPE aurait indiqué le problème de manière beaucoup plus claire. Ainsi, vous devrez effectuer une "Vérification de l'objet Null" au lieu d'une vérification de null, et vous n'avez rien gagné, en fait, vous avez perdu en clarté. De nos jours, si je ne peux pas éviter null, je le documente simplement de manière claire et c'est tout.
Écrire this.bar = Objects.requireNonNull(bar);
est un bon usage de cette méthode, car vous n'êtes pas sur le point d'utiliser this.bar
. De cette manière, vous obtenez l'exception lorsqu'un objet nul invalide est passé, plutôt que lorsque vous essayez de l'utiliser. Cependant, il est souvent utilisé de cette façon: Objects.requireNonNull(getThing()).doThingStuff();
Ici, l'appel à Objects.requireNonNull()
ne change pas du tout le comportement, il lance le NPE de toute façon. Il est préférable de l'utiliser lorsque vous sauvegardez un objet pour une utilisation ultérieure. Dans mon deuxième exemple, l'exception est utile. Elle aide à traquer le bug.
Devrions-nous suggérer d'utiliser des exceptions pour le flux de contrôle? Bien que ce soit techniquement une solution qui fonctionne, les programmeurs devraient se souvenir que les exceptions ne devraient être utilisées que pour attraper des situations inattendues. Lors de la validation de l'entrée d'un utilisateur, une entrée invalide ne devrait idéalement pas entraîner le déclenchement d'exceptions.
Si vous utilisez (ou prévoyez d'utiliser) un IDE Java comme JetBrains IntelliJ IDEA, Eclipse ou Netbeans ou un outil comme Findbugs, vous pouvez utiliser des annotations pour résoudre ce problème.
Fondamentalement, vous avez @Nullable
et @NotNull
.
Vous pouvez les utiliser dans une méthode et des 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 compilerait pas (dans IntelliJ IDEA).
Lorsque vous utilisez la première fonction helloWorld()
dans une autre partie du 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 null
.
Utilisation d'un paramètre
void someMethod(@NotNull someParameter) { }
si vous écrivez quelque chose comme :
someMethod(null);
Ceci ne compilerait pas.
Dernier exemple utilisant @Nullable
@Nullable iWantToDestroyEverything() { return null; }
En faisant cela
iWantToDestroyEverything().something();
Et vous pouvez être sûr que cela ne se produira pas. :)
C'est un moyen utile de permettre au compilateur de vérifier quelque chose de plus que ce qu'il fait habituellement et de renforcer vos contrats. Malheureusement, ce n'est pas pris en charge par tous les compilateurs.
Dans IntelliJ IDEA 10.5 et plus, ils ont ajouté la prise en charge de toute autre implémentation de @Nullable
@NotNull
.
Voir l'article de blog Annotations @Nullable/@NotNull plus flexibles et configurables.
Je trouve étrangement agaçant que les interfaces @NotNull
et @Nullable
se trouvent dans le package com.sun.istack.internal
. (Je suppose que j'associe com.sun à des avertissements concernant l'utilisation d'une API propriétaire.)
La portabilité du code devient nulle avec JetBrains. Je réfléchirais à deux fois avant de m'attacher au niveau de l'IDE. Comme l'a dit Jacek S, ils font de toute façon partie de la JSR, que je pensais être la JSR303 d'ailleurs.
Si votre méthode est appelée de l'extérieur, 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 nul.
S'il s'agit d'une méthode interne (qui ne fait pas partie d'une API), contentez-vous de documenter le fait 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 se contente de transmettre la valeur, et que la méthode suivante la transmet à son tour, cela peut poser problème. Dans ce cas, vous voudrez peut-être vérifier l'argument comme décrit ci-dessus.
Cela dépend vraiment. Je trouve que j'ai souvent recours à quelque chose comme ça :
if (object == null) {
// quelque chose
} else {
// quelque chose d'autre
}
Je fais donc une bifurcation, et je fais deux choses complètement différentes. Il n'y a pas de morceau de code laid, car j'ai vraiment besoin de faire deux choses différentes en fonction des données. Par exemple, dois-je travailler sur l'entrée, ou dois-je calculer une bonne valeur par défaut ?
C'est en fait rare que j'utilise l'idiome "if (object != null && ...
".
Il serait peut-être plus facile de vous donner des exemples si vous montrez des exemples de l'endroit où vous utilisez généralement cet idiome.
Quel est l'intérêt de lancer une IllegalArgumentException ? Je pense qu'une NullPointerException serait plus claire, et cela serait également lancé si vous ne faites pas la vérification de null vous-même. Je préfère utiliser assert ou rien du tout.
Il est peu probable que toute autre valeur que null soit acceptable. Vous pourriez avoir IllegalArgumentException, OutOfRangeException etc etc. Parfois, cela a du sens. D'autres fois, vous finissez par créer beaucoup de classes d'exception qui n'ajoutent aucune valeur, puis vous utilisez simplement IllegalArgumentException. Il n'a aucun sens d'avoir une exception pour une saisie nulle, et une autre pour tout le reste.
Oui, je suis d'accord avec le principe du "fail-fast", mais dans l'exemple donné ci-dessus, la valeur n'est pas transmise, mais c'est l'objet sur lequel une méthode doit être appelée. Donc cela échoue tout aussi rapidement, et ajouter une vérification de nulle juste pour lancer une exception qui serait de toute façon lancée au même moment et au même endroit ne semble pas faciliter le débogage.
Wow, je déteste presque ajouter une autre réponse alors que nous avons 57 façons différentes de recommander le NullObject pattern
, mais je pense que certaines personnes intéressées par cette question pourraient aimer savoir qu'il y a une proposition sur la table pour Java 7 pour ajouter la "gestion sûre du null" - 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();
}
Le ?.
signifie dé-référencer uniquement l'identifiant de gauche s'il n'est pas nul, sinon évaluer le reste de l'expression comme null
. Certaines personnes, comme le membre de Java Posse Dick Wall et les votants à Devoxx adorent vraiment cette proposition, mais il y a aussi de l'opposition, parce qu'elle encouragerait en réalité une utilisation plus fréquente de null
comme valeur sentinelle.
Mise à jour: Une proposition officielle pour un opérateur null-safe dans 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 idée.
Mise à jour: La proposition d'opérateur null-safe n'a pas été retenue dans le Projet Coin. Vous ne verrez donc pas cette syntaxe dans Java 7.
Je pense que c'est faux. Il devrait y avoir un moyen de spécifier qu'une variable donnée est TOUJOURS non nulle.
Mise à jour : la proposition ne se fera pas en Java7. Voir blogs.sun.com/darcy/entry/project_coin_final_five .
Mais sur la même page, consultez le lien vers types.cs.washington.edu/jsr308 pour des informations sur l'utilisation du cadre Checker pour ajouter les annotations de type @Nullable et @NonNull en Java 7.
Vous pouvez configurer votre IDE pour vous avertir des accès potentiels à null. Par exemple, dans Eclipse, consultez Préférences > Java > Compilateur > Erreurs/Avertissements/Analyse null.
Si vous souhaitez définir une nouvelle API où les valeurs indéfinies ont du sens, utilisez le Pattern Option (peut être familier aux langages fonctionnels). Il présente les avantages suivants :
Java 8 dispose d'une classe intégrée Optional
(recommandée) ; pour les versions antérieures, il existe des alternatives de bibliothèque, par exemple l'Optionnel Guava de Guava ou l'Option de FunctionalJava. Mais comme de nombreux motifs de style fonctionnel, l'utilisation de l'Option en Java (même 8) entraîne une certaine quantité de code d'amorçage, que vous pouvez réduire en utilisant un langage JVM moins verbeux, par exemple Scala ou Xtend.
Si vous devez interagir avec une API qui peut renvoyer des valeurs nulles, vous ne pouvez pas faire grand-chose en Java. Xtend et Groovy disposent de l'opérateur Elvis ?: et de l'opérateur de déréférencement null-sûr ?., mais notez que cela renvoie null en cas de référence nulle, reportant ainsi le traitement approprié de null.
En effet, le modèle Option est génial. Certains équivalents en Java existent. Guava contient une version limitée de cela appelée Optionnelle qui exclut la plupart des fonctionnalités fonctionnelles. En Haskell, ce modèle est appelé Peut-être.
@Luca Molteni: Tu as tout à fait raison, j'ai déjà commenté sur le post pour demander de l'étendre. :)
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
144 votes
@Shervin Encourager les valeurs nulles rend le code moins compréhensible et moins fiable.
85 votes
Ne pas utiliser null est supérieur à la plupart des autres suggestions ici. Lancez des exceptions, ne renvoyez pas ou n'autorisez pas les nulls. En passant - le mot clé 'assert' est inutile, car il est désactivé par défaut. Utilisez un mécanisme d'échec toujours activé.
0 votes
Vous pouvez créer une classe qui vérifiera les valeurs nulles ou les objets nuls. Cela vous aidera à améliorer la réutilisabilité.. stackoverflow.com/a/16833309/1490962
0 votes
Utilisez Lombok, vous obtenez @NotNull
1 votes
N'existe-t-il pas un pattern de conception qui parle de créer un objet nul? Ainsi, lors de l'instanciation d'un nouvel objet, vous utilisez toujours cet objet nul (même super classe, mêmes méthodes [mais vides]) et plus tard vous définissez l'objet sur l'objet complet lorsque vous en avez besoin. Vous voudrez peut-être consulter une question similaire: stackoverflow.com/questions/9162371/… et ces informations sur le pattern Objet Null: fr.wikipedia.org/wiki/Null_Object_pattern
8 votes
Les nulls devraient être évités dans le code de haut niveau. Tony Hoare, qui a inventé les références nulles, les appelle "une erreur d'un milliard de dollars". Jetez un coup d'œil ici pour quelques idées.
4 votes
Il semble être en Java 8 : static Objects.isNull(Object o) docs.oracle.com/javase/8/docs/api/java/util/Objects.html
1 votes
Que diriez-vous d'encapsuler l'objet avec Optionnel. Utilisez Optionnel partout où vous voyez la possibilité de valeurs nulles
11 votes
La confusion la plus courante autour de null est lorsque les gens retournent null au lieu d'une collection vide. Cela me rend fou à chaque fois. Arrêtez d'utiliser les nulls, et vous vivrez dans un monde meilleur. De plus, étendez votre code avec le mot-clé
final
et vous vivrez dans un monde encore meilleur.1 votes
@Abhishekkapoor Les optionnels ne sont pas censés être utilisés en tant que paramètres ou valeurs de retour. Ils ne doivent être utilisés que dans la programmation fonctionnelle (par exemple les flux).
0 votes
@Abhishekkapoor Utiliser l'option sur les paramètres d'entrée est une idée compréhensible, mais c'est en fait une très mauvaise idée en pratique. J'ai un blog à ce sujet où je donne plusieurs exemples, tous tirés du code de production, où ces pratiques causent plus de problèmes qu'elles n'en valent la peine. Si cela vous intéresse, lisez-le sur github.com/SwingGuy1024/Blog/blob/master/…
0 votes
Utiliser Optionals ou Kotlin
0 votes
Probablement vous cherchiez
Optional.ofNullable(x).ifPresent(xV -> xV.someAction());
0 votes
Je suis un peu en désaccord ici. Si un objet a des propriétés qui peuvent légitimement ne pas avoir de valeur, je trouve que l'utilisation de "null" pour représenter ce fait est aussi valable que toute autre représentation que j'ai trouvée. Le fait que vous obteniez une NPE si vous oubliez de vérifier cet état légitime est une bonne chose ; si vous utilisez plutôt une valeur d'énumération UNKNOWN, alors un échec de vérification passera inaperçu.