list.stream().map(Foo::getAttr)
... retourne un flux avec un élément, avec une valeur de null .
Le JavaDoc pour findAny()
(et findFirst()
) dit:
Retours:
une option décrivant un élément de ce flux, ou un vide en option si le flux est vide
Jets:
NullPointerException - si l'élément sélectionné est nul
Alors findAny()
fait exactement comme documenté: il est la sélection d'un nul, et en conséquence, jetant NullPointerException
.
Cela est logique car Optional
est (toujours selon JavaDoc, mais non souligné):
Un objet conteneur qui peut ou non contenir une valeur non nulle
. .. ce qui signifie que vous pouvez garantir que Optional.ifPresent(x -> x.method())
ne lancera jamais NullPointerException
en raison de x
étant nulle.
Donc, findAny()
n'a pas pu renvoyer Optional.of(null)
. Et Optional.empty()
signifie que le flux était vide, pas qu'il ait trouvé une valeur nulle.
De nombreuses parties de l'infrastructure Stream
/Optional
découragent l'utilisation de valeurs nulles.
Vous pouvez contourner ce problème en mappant les valeurs NULL à Optionals
, pour donner un Optional<Optional<Foo>>
- ce qui semble un peu compliqué, mais est une représentation précise de votre domaine. Optional.empty()
signifie que le flux était vide. Optional.of(Optional.empty())
signifie qu'il a trouvé un élément nul:
list.stream().map(Foo::getAttr).map(Optional::ofNullable).findAny()
Voir aussi [Pourquoi findFirst() une NullPointerException si le premier élément qu'il trouve est nul?] (Https://stackoverflow.com/q/32466799/2711488) – Holger