How should we manage jdk8 stream for null values
Stuart's answer provides a great explanation, but I'd like to provide another example.
I ran into this issue when attempting to perform a reduce
on a Stream containing null values (actually it was LongStream.average()
, which is a type of reduction). Since average() returns OptionalDouble
, I assumed the Stream could contain nulls but instead a NullPointerException was thrown. This is due to Stuart's explanation of null v. empty.
So, as the OP suggests, I added a filter like so:
list.stream()
.filter(o -> o != null)
.reduce(..);
Or as tangens pointed out below, use the predicate provided by the Java API:
list.stream()
.filter(Objects::nonNull)
.reduce(..);
From the mailing list discussion Stuart linked: Brian Goetz on nulls in Streams
Although the answers are 100% correct, a small suggestion to improve null
case handling of the list itself with Optional:
List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
The part Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
will allow you to handle nicely the case when listOfStuff
is null and return an emptyList instead of failing with NullPointerException.
Current thinking seems to be to "tolerate" nulls, that is, to allow them in general, although some operations are less tolerant and may end up throwing NPE. See the discussion of nulls on the Lambda Libraries expert group mailing list, specifically this message. Consensus around option #3 subsequently emerged (with a notable objection from Doug Lea). So yes, the OP's concern about pipelines blowing up with NPE is valid.
It's not for nothing that Tony Hoare referred to nulls as the "Billion Dollar Mistake." Dealing with nulls is a real pain. Even with classic collections (without considering lambdas or streams) nulls are problematic. As fge mentioned in a comment, some collections allow nulls and others do not. With collections that allow nulls, this introduces ambiguities into the API. For example, with Map.get(), a null return indicates either that the key is present and its value is null, or that the key is absent. One has to do extra work to disambiguate these cases.
The usual use for null is to denote the absence of a value. The approach for dealing with this proposed for Java SE 8 is to introduce a new java.util.Optional
type, which encapsulates the presence/absence of a value, along with behaviors of supplying a default value, or throwing an exception, or calling a function, etc. if the value is absent. Optional
is used only by new APIs, though, everything else in the system still has to put up with the possibility of nulls.
My advice is to avoid actual null references to the greatest extent possible. It's hard to see from the example given how there could be a "null" Otter. But if one were necessary, the OP's suggestions of filtering out null values, or mapping them to a sentinel object (the Null Object Pattern) are fine approaches.