109 votes

Comment gérer les flux jdk8 pour les valeurs nulles ?

Je sais que le sujet peut être un peu in advance comme 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 particulièrement la partie liée à la nouvelle API de collecte connue sous le nom de Stream.

Voici l'exemple tel qu'il est donné dans le Article du magazine Java (c'est un algorithme de la population des 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 la suivante : 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 levée mais peut-être suis-je encore 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 traité ?

Si cela déclenche réellement une exception NullPointerException, je trouve cette fonctionnalité assez dangereuse et il faudra l'utiliser 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 n'est jamais générer de null otter ou un objet spécial NullOtter à traiter.

Quelle est la meilleure option, ou toute autre option ?

146voto

Stas S Points 80

Bien que les réponses soient 100% correctes, une petite suggestion pour améliorer null traitement de la liste elle-même avec En option :

 List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
                .orElseGet(Collections::emptyList)
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

La partie Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList) vous permettra de gérer joliment le cas où listOfStuff est nulle et renvoie une liste vide au lieu d'échouer avec NullPointerException.

73voto

rmarles Points 21

La réponse de Stuart fournit une excellente explication, mais j'aimerais fournir un autre exemple.

J'ai rencontré ce problème en essayant d'effectuer une reduce sur un Stream contenant des valeurs nulles (en fait, c'était LongStream.average() qui est un type de réduction). Puisque average() renvoie OptionalDouble J'ai supposé que le flux pouvait contenir des valeurs nulles, mais au lieu de cela, une exception NullPointerException a été levée. Ceci est dû à L'explication de Stuart de nullité 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 le souligne Tangens ci-dessous, utilisez le prédicat fourni par l'API Java :

list.stream()
    .filter(Objects::nonNull)
    .reduce(..);

De la discussion de la liste de diffusion dont Stuart a donné le lien : Brian Goetz sur les nulls dans les flux

46voto

Stuart Marks Points 8927

La pensée actuelle semble être de "tolérer" les 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. Voir le discussion sur les nuls sur la liste de diffusion du groupe d'experts Lambda Libraries, en particulier ce message . Un consensus autour de l'option n°3 s'est ensuite dégagé (avec une objection notable de Doug Lea). Donc oui, la préoccupation de l'OP concernant l'explosion des pipelines avec les NPE est valide.

Ce n'est pas pour rien que Tony Hoare appelait les nulls les "Billion Dollar Mistake". Le traitement des valeurs nulles est une véritable plaie. Même avec les collections classiques (sans tenir compte des lambdas ou des flux), les valeurs nulles sont problématiques. Comme fge Comme mentionné dans un commentaire, certaines collections autorisent les valeurs nulles et d'autres non. Avec les 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 désambiguïser ces cas.

L'utilisation habituelle de null est de dénoter l'absence d'une valeur. L'approche proposée pour Java SE 8 est d'introduire un nouveau paramètre de type "null". java.util.Optional qui encapsule la présence/absence d'une valeur, ainsi que les comportements consistant à fournir une valeur par défaut, à lancer une exception, à 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 toujours s'accommoder de la possibilité de nuls.

Je vous conseille d'éviter autant que possible les références nulles réelles. Il est difficile de voir dans l'exemple donné comment il pourrait y avoir une Loutre "nulle". Mais s'il en fallait une, les suggestions du PO de filtrer les valeurs nulles, ou de les faire correspondre à un objet sentinelle (l'objet Modèle d'objet nul ) sont de bonnes approches.

21voto

Andy Thomas Points 30979

Si vous souhaitez simplement filtrer les valeurs nulles d'un flux, vous pouvez simplement utiliser une référence à la méthode java.util.Objects.nonNull(Objet) . De sa documentation :

Cette méthode existe pour être utilisée comme Prédicat , filter(Objects::nonNull)

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 va s'imprimer :

Foo
Bar

7voto

Ilan M Points 285

Un exemple pour éviter les nullités, par exemple en utilisant le filtre avant le groupingBy.

Filtre les instances nulles avant le groupingBy.

Voici un exemple

MyObjectlist.stream()
            .filter(p -> p.getSomeInstance() != null)
            .collect(Collectors.groupingBy(MyObject::getSomeInstance));

Prograide.com

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.

Powered by:

X