How should we manage jdk8 stream for null values

JavaNullJava 8Java Stream

Java Problem Overview


I know the subject may be a bit in advance as the JDK8 is not yet released (and not for now anyway..) but I was reading some articles about the Lambda expressions and particularly the part related to the new collection API known as Stream.

Here is the example as given in the Java Magazine article (it is an otter population algorithm..):

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());

My question is what happen if in the middle of the Set internal iteration, one of the otter is null?

I would expect a NullPointerException to be thrown but maybe am I still stuck in the previous development paradigm (non-functional), can someone enlighten me as how this should be handled?

If this really throw a NullPointerException, I find the feature quite dangerous and will have to be used only as below:

  • Developer to ensure there is no null value (maybe using a previous .filter(o -> o != null))
  • Developer to ensure the application is never generating null otter or a special NullOtter object to deal with.

What is the best option, or any other option?

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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

Solution 3 - Java

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.

Solution 4 - Java

If you just want to filter null values out of a stream, you can simply use a method reference to java.util.Objects.nonNull(Object). From its documentation:

>This method exists to be used as a Predicate, filter(Objects::nonNull)

For example:

List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null);
	
list.stream()
    .filter( Objects::nonNull )  // <-- Filter out null values
    .forEach( System.out::println );

This will print:

Foo
Bar

Solution 5 - Java

An example how to avoid null e.g. use filter before groupingBy##

Filter out the null instances before groupingBy.

Here is an example

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

Solution 6 - Java

If you do not want to iterate two times (filter + map or any). Try this.

private static void trimAll() {
    String[] emtLne = {"", " ", "  cc  ", null, "      xx   "};
    System.out.println(Arrays.stream(emtLne).map(val -> (val != null) ? val.trim() : "").collect(Collectors.joining()));
}

Output
ccxx

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionclementView Question on Stackoverflow
Solution 1 - JavaJohnnyView Answer on Stackoverflow
Solution 2 - JavabparryView Answer on Stackoverflow
Solution 3 - JavaStuart MarksView Answer on Stackoverflow
Solution 4 - JavaAndy ThomasView Answer on Stackoverflow
Solution 5 - JavaIlan MView Answer on Stackoverflow
Solution 6 - JavasmilyfaceView Answer on Stackoverflow