Bonjour chers développeurs Java,
Je sais que le sujet peut être un peu in advance
car le JDK8 n'est pas encore sorti (et pas pour l'instant en tout cas ..) mais je lisais quelques articles sur les expressions Lambda et en particulier la partie liée à la nouvelle API de collection connue sous le nom de Stream.
Voici l'exemple donné dans l' article de Java Magazine (il s'agit d'un algorithme de population de loutres ..):
Set<Otter> otters = getOtters();
System.out.println(otters.stream()
.filter(o -> !o.isWild())
.map(o -> o.getKeeper())
.filter(k -> k.isFemale())
.into(new ArrayList<>())
.size());
Ma question est que se passe-t-il si au milieu de l'itération interne Set, l'une des loutres est nulle?
Je m'attendrais à ce qu'une exception NullPointerException soit lancée, mais je suis peut-être toujours coincé dans le paradigme de développement précédent (non fonctionnel), quelqu'un peut-il m'éclairer sur la façon dont cela devrait être géré?
Si cela lève vraiment une NullPointerException, je trouve la fonctionnalité assez dangereuse et devra être utilisée uniquement comme ci-dessous:
- Développeur pour s'assurer qu'il n'y a pas de valeur nulle (peut-être en utilisant un précédent .filter (o -> o! = Null))
- Développeur pour s'assurer que l'application ne génère jamais une loutre nulle ou un objet NullOtter spécial à traiter.
Quelle est la meilleure option ou toute autre option?
Merci!
la source
filter(Objects::nonNull)
avecObjects
dejava.utils
Réponses:
La pensée actuelle semble être de «tolérer» les valeurs nulles, c'est-à-dire de les autoriser en général, bien que certaines opérations soient moins tolérantes et puissent finir par lancer des NPE. Consultez la discussion sur les valeurs nulles sur la liste de diffusion du groupe d'experts des bibliothèques Lambda, en particulier ce message . Un consensus autour de l'option 3 est apparu par la suite (avec une objection notable de Doug Lea). Alors oui, la préoccupation du PO concernant l'explosion de pipelines avec du NPE est valide.
Ce n'est pas pour rien que Tony Hoare a qualifié les nulls d ' «erreur d'un milliard de dollars». Traiter les nulls est une vraie douleur. Même avec des collections classiques (sans tenir compte des lambdas ou des flux), les valeurs nulles sont problématiques. Comme fge l'a mentionné dans un commentaire, certaines collections autorisent les valeurs nulles et d'autres non. Avec des collections qui autorisent les valeurs nulles, cela introduit des ambiguïtés dans l'API. Par exemple, avec Map.get () , un retour nul indique soit que la clé est présente et que sa valeur est nulle, soit que la clé est absente. Il faut faire un travail supplémentaire pour lever l'ambiguïté de ces cas.
L'utilisation habituelle de null est de désigner l'absence de valeur. L'approche pour traiter ce problème proposée pour Java SE 8 est d'introduire un nouveau
java.util.Optional
type, qui encapsule la présence / l'absence d'une valeur, ainsi que les comportements consistant à fournir une valeur par défaut, à lancer une exception, ou à appeler une fonction, etc. si la valeur est absente.Optional
n'est utilisé que par les nouvelles API, cependant, tout le reste du système doit encore supporter la possibilité de valeurs nulles.Mon conseil est d'éviter au maximum les références nulles réelles. Il est difficile de voir à partir de l'exemple donné comment il pourrait y avoir un Otter "nul". Mais si cela était nécessaire, les suggestions de l'OP de filtrer les valeurs nulles, ou de les mapper à un objet sentinelle (le modèle d'objet nul ) sont de bonnes approches.
la source
null
nul, c'est pourquoi. Acc. à une enquête que j'ai vue (je ne la trouve pas), NPE est l'exception numéro 1 en Java. SQL n'est pas un langage de programmation de haut niveau, certainement pas fonctionnel, qui méprise null, donc il s'en fiche.Bien que les réponses soient correctes à 100%, une petite suggestion pour améliorer la
null
gestion des cas de la liste elle-même avec facultatif :La partie
Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
vous permettra de bien gérer le cas oùlistOfStuff
est null et de renvoyer un emptyList au lieu d'échouer avec NullPointerException.la source
La réponse de Stuart fournit une excellente explication, mais j'aimerais donner un autre exemple.
J'ai rencontré ce problème en essayant d'effectuer un
reduce
sur un flux contenant des valeurs nulles (en fait, c'étaitLongStream.average()
un type de réduction). Depuis le retour de average ()OptionalDouble
, j'ai supposé que le Stream pouvait contenir des valeurs nulles, mais à la place, une NullPointerException a été lancée. Cela est dû à l'explication de Stuart de null contre vide.Donc, comme le suggère l'OP, j'ai ajouté un filtre comme ceci:
list.stream() .filter(o -> o != null) .reduce(..);
Ou comme tangens l'a souligné ci-dessous, utilisez le prédicat fourni par l'API Java:
De la discussion de la liste de diffusion Stuart a lié: Brian Goetz sur les nulls dans Streams
la source
Si vous souhaitez simplement filtrer les valeurs nulles d'un flux, vous pouvez simplement utiliser une référence de méthode à java.util.Objects.nonNull (Object) . De sa documentation:
Par exemple:
List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null); list.stream() .filter( Objects::nonNull ) // <-- Filter out null values .forEach( System.out::println );
Cela imprimera:
la source
Un exemple comment éviter null, par exemple, utilisez le filtre avant de grouper
Filtrez les instances nulles avant groupingBy.
Voici un exempleMyObjectlist.stream() .filter(p -> p.getSomeInstance() != null) .collect(Collectors.groupingBy(MyObject::getSomeInstance));
la source