107

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?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
clement
  • 1,491
  • 2
  • 10
  • 11
  • 3
    I'd say it is up to the programmer to do the right thing here; the JVM and compiler can only do so much. Note that some collection implementations will not allow null values, however. – fge Jun 13 '13 at 07:06
  • 27
    You can use `filter(Objects::nonNull)` with `Objects` from `java.utils` – Benj Jul 22 '16 at 14:15

6 Answers6

140

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.

Johnny
  • 14,397
  • 15
  • 77
  • 118
  • 3
    I like this, avoids explicitly checking for null. – Chris Apr 03 '18 at 19:25
  • 2
    this looks best clear .. nice and exactly what I needed – Abdullah Al Noman Jun 20 '18 at 14:01
  • 1
    It's explicitly checking for null, only in a different way. If it's allowed to be null, it should be an Optional, that's the idea, right? Ban all the null values with optionals. Moreover, it is bad practice to return null instead of an empty list, so it shows two code smells if I see this: no Optionals being used, and no empty streams being returned. And the latter is available for over 20 years, so that's mature... – Koos Gadellaa Oct 22 '19 at 12:53
  • what if I want to return a null instead empty list? – Ashburn RK Jun 10 '20 at 19:29
  • 3
    @AshburnRK it's a bad practice. You should return an empty list. – Johnny Jun 10 '20 at 20:55
  • @Chris it avoids checking for null but now it creates an empty list that uses more memory, how is that better? sacrifice performance for code readability ? – Diego Ramos May 03 '22 at 17:44
  • @DiegoRamos depends on what you're optimizing for. – Chris May 05 '22 at 03:45
72

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

Community
  • 1
  • 1
bparry
  • 1,456
  • 13
  • 9
46

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.

Community
  • 1
  • 1
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
  • 4
    Why avoid nulls? They are used in databases extensively. – Raffi Khatchadourian Aug 25 '15 at 16:48
  • 6
    @RaffiKhatchadourian Yes, nulls are used in databases, but are equally problematic. See [this](http://stackoverflow.com/questions/163434/are-nulls-in-a-relational-database-okay) and [this](http://dba.stackexchange.com/questions/5222/why-shouldnt-we-allow-nulls) and read **all** the answers and comments. Also consider the impact of SQL null on boolean expressions: https://en.wikipedia.org/wiki/Null_%28SQL%29#Law_of_the_excluded_fourth_.28in_WHERE_clauses.29 ... this is rich source of query errors. – Stuart Marks Aug 27 '15 at 01:07
  • 1
    @RaffiKhatchadourian Because `null` sucks, that's why. Acc. to a survey I saw(can't find it), NPE is the number 1 exception in Java. SQL is not a high-level programming language, certainly not functional, which despises null, so it doesn't care. – Abhijit Sarkar Jul 07 '17 at 08:30
20

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
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
7

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));
Jon Onstott
  • 13,499
  • 16
  • 80
  • 133
Ilan M
  • 299
  • 3
  • 8
0

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

smilyface
  • 5,021
  • 8
  • 41
  • 57