Plusieurs fois, je me retrouve à vérifier null lors de la récupération d'une valeur dans une hiérarchie de données pour éviter les NullPointerExceptions, que je trouve sujettes à des erreurs et qui nécessitent beaucoup de passe-partout.
J'ai écrit une routine très simple qui me permet d'ignorer la vérification nulle lors de la récupération d'un objet ...
public final class NoNPE {
public static <T> T get(NoNPEInterface<T> in) {
try {
return in.get();
} catch (NullPointerException e) {
return null;
}
}
public interface NoNPEInterface<T> {
T get();
}
}
Je l'utilise un peu comme ça ...
Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());
Ce qui précède m'a permis d'obtenir un objet Room ou un null, sans avoir à vérifier tous les niveaux parent.
Que pensez-vous de ce qui précède? Suis-je en train de créer un motif problématique? Existe-t-il une meilleure façon de procéder à votre avis?
java.util.Optional
au lieu de null pour représenter les données manquantes? Cela fournit des utilitaires pratiques à la fois pour le cas que vous décrivez et les cas où vous souhaitez continuer avec des données par défaut plutôt que de simplement renvoyer une condition d'échec à la fin de la chaîne.Option
(ouMaybe
) monade :)Réponses:
Votre solution est très intelligente. Le problème que je vois est le fait que vous ne savez pas pourquoi vous en avez un
null
? Est-ce parce que la maison n'avait pas de pièces? Était-ce parce que la ville n'avait pas de maisons? Est-ce parce que le pays n'a pas de villes? Était-ce parce qu'il y avait unnull
dans la position 0 de la collection à cause d'une erreur même quand il y a des maisons dans les positions 1 et plus?Si vous utilisez largement la
NonPE
classe, vous aurez de sérieux problèmes de débogage. Je pense qu'il vaut mieux savoir où exactement la chaîne est brisée que d'en obtenir silencieusement unenull
qui pourrait cacher une erreur plus profonde.Cela viole également la loi de Déméter :
country.getTown().getHouses().get(0).getLivingRoom()
. Plus souvent qu'autrement, la violation d'un bon principe vous oblige à mettre en œuvre des solutions peu orthodoxes pour résoudre le problème causé par la violation de ce principe.Ma recommandation est que vous l'utilisiez avec prudence et essayez de résoudre le défaut de conception qui vous oblige à encourir l' antipattern de l'épave du train (vous n'avez donc pas à l'utiliser
NonPE
partout). Sinon, vous pourriez avoir des bogues difficiles à détecter.la source
Option
monade, vous ne vous souciez pas de savoir où se trouve la valeur absente dans la chaîne. Lorsque vous vous en souciez, vous utiliserez probablement un type différent, tel queEither
.?.
et aux?[]
opérateurs. Un exemple de cas où vous voudrez peut-être utiliser une telle chose est les paramètres côté serveur hiérarchiques.var shouldDoThing = settings?.a?.b?.c ?? defaultSetting;
Peu importe pourquoi une partie de cela était nulle? Vous n'avez peut-être pas pu récupérer les paramètres. Vous avez peut-être décidé de supprimer une section des paramètres. Dans tous les cas, vous ne pouvez jamais vraiment compter sur l'obtention des paramètres du serveur, donc une valeur par défaut est généralement une bonne idée, et vous ne vous soucierez probablement pas pourquoi vous ne pouvez pas obtenir le paramètre réel, sauf si cela se produit très souvent alors qu'il ne devrait pas .settings.a.b.c
. Là encore, il s'agit d'un seul exemple isolé.L'idée est bonne, vraiment bonne en fait. Depuis Java 8, les
Optional
types existent, une explication détaillée peut être trouvée dans Java Optional type . Un exemple avec ce que vous avez publié estEt plus loin.
la source
Optional
c'est la solution la plus lisible des deux, ne serait-ce que parce que - contrairement à votre proposition - c'est un idiome très courant . Il est encore plus concis que le vôtre!Votre méthode fonctionne assez bien pour son objectif, bien que renvoyer
null
s lorsque vous obtenez unNullPointerException
son de mauvaise conception.Essayez d'éviter les
null
s lorsque vous le pouvez et ne les passez que lorsqu'ils représentent quelque chose ou ont une signification particulière et ne les renvoyez que lorsqu'ils représentent / signifient quelque chose - sinon vous devriez jeter aNullPointerException
. Cela évite les bugs et la confusion. Si unObject
ne devrait pas l'êtrenull
, unNullPointer
devrait être jeté. Si un objet peut l'être,null
rien ne se passera mal lors de sa transmission. Sinon, votre méthode ci-dessus fonctionne.la source
Je peux ressentir votre douleur, mais la solution proposée est une mauvaise idée.
NoNPE.get
.Optional.map
c'est ce que vous recherchez.En remarque,
NoNPEInterface
est un doublon dejava.util.function.Supplier
.Dans certains cas, vous pourriez envisager d'utiliser une expression d'évaluation utils qui sont présents dans de nombreux cadres (par exemple: EL, SpEL):
la source