web-dev-qa-db-fra.com

Comment créer au mieux un flux Java 8 à partir d'un objet nullable?

Quel est le meilleur moyen/idiomatique de faire un contrôle nul avant d’obtenir un flux?

J'ai une méthode qui reçoit une List qui pourrait être nulle. Donc, je ne peux pas simplement appeler .stream() sur la valeur passée. Existe-t-il une aide statique qui me donnerait un flux vide si une valeur est nulle?

23
checketts

Je suis d'accord avec Stuart Marks que list == null ? Stream.empty() : list.stream() est le meilleur moyen de le faire (voir sa réponse ), ou du moins le meilleur moyen de le faire avant Java 9 (voir modification ci-dessous), mais je ' Laissez cette réponse en suspens pour démontrer l'utilisation de l'API facultative.

<T> Stream<T> getStream(List<T> list) {
    return Optional.ofNullable(list).map(List::stream).orElseGet(Stream::empty);
}

Edit: Java 9 a ajouté la méthode statique Stream.<T>ofNullable(T) , qui renvoie le flux vide avec un argument null, sinon un flux dont l’argument est le seul élément. Si l'argument est une collection, nous pouvons/ flatMap le transformer en flux.

<T> Stream<T> fromNullableCollection(Collection<? extends T> collection) {
    return Stream.ofNullable(collection).flatMap(Collection::stream);
}

Cela n'abuse pas de l'API facultative telle que discutée par Stuart Marks, et contrairement à la solution d'opérateur ternaire, il n'y a aucune possibilité d'exception de pointeur nul (comme si vous ne faisiez pas attention et bousilleriez l'ordre des opérandes). Il fonctionne également avec un caractère générique de limite supérieure sans avoir besoin de SuppressWarnings("unchecked") grâce à la signature de flatMap. Vous pouvez ainsi obtenir un Stream<T> à partir d'une collection d'éléments de n'importe quel sous-type de T.

35
gdejohn

Dans les autres réponses, l'instance Optional est créée et utilisée strictement dans la même instruction. La classe Optional est principalement utile pour communiquer avec l'appelant sur la présence ou l'absence d'une valeur de retour, fusionnée avec la valeur réelle si présente. Son utilisation intégrale dans une seule méthode semble inutile.

Me laisser proposer la technique plus prosaïque suivante:

static <T> Stream<T> nullableListToStream(List<T> list) {
    return list == null ? Stream.empty() : list.stream();
}

Je suppose que l'opérateur ternaire est quelque peu déclassé ces derniers temps, mais je pense que c'est la solution la plus simple et la plus efficace.

Si j’écrivais cela pour de vrai (c’est-à-dire pour une vraie bibliothèque et pas seulement un exemple de code sur Stack Overflow), je mettrais des caractères génériques afin que le type de retour du flux puisse varier du type List. Oh, et ça peut être une collection, puisque c'est là que la méthode stream() est définie:

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll) {
    return coll == null ? Stream.empty() : (Stream<T>)coll.stream();
}

(La suppression de l'avertissement est nécessaire en raison de la conversion de Stream<? extends T> en Stream<T> qui est sûre, mais le compilateur l'ignore.)

12
Stuart Marks

La meilleure chose à laquelle je puisse penser serait d’utiliser Optional avec la méthode orElseGet.

return Optional.ofNullable(userList)
                .orElseGet(Collections::emptyList)
                .stream()
                .map(user -> user.getName())
                .collect(toList());

Mis à jour avec @ Misha, suggère d'utiliser Collections::emptyList sur ArrayList::new

12
checketts

Apache commons-collections4:

CollectionUtils.emptyIfNull(list).stream()
5
piotrek

Personnellement, je considère que null est obsolète et utilise Facultatif dans la mesure du possible, malgré la surcharge (minuscule) de performances. J'utilise donc l'interface de Stuart Marks avec une implémentation basée sur gdejohn, c'est-à-dire.

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll)
{
    return (Stream<T>) Optional.ofNullable(coll)
                           .map(Collection::stream)
                           .orElseGet(Stream::empty);
}
0