Java Null-Safe Streams from Collections

1. Overview

In this tutorial, we’ll see how to create null-safe streams from Java
collections.

To start with, some familiarity with Java 8’s Method References, Lambda
Expressions, Optional and Stream API is required to fully understand
this material.

If you are unfamiliar with any of these topics, kindly take a look at
our previous articles first:
New Features in Java 8,
Guide To Java 8 Optional and
Introduction to
Java 8 Streams
.

2. Maven Dependency

Before we begin, there’s one Maven dependency that we’re going to need
for certain scenarios:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.2</version>
</dependency>

The
commons-collections4
library can be downloaded from Maven Central.

3. Creating Streams from Collections

The basic approach to creating a
Stream from any
type of Collection is to call the stream() or parallelStream()
methods on the collection depending on the type of stream that is
required:

Collection<String> collection = Arrays.asList("a", "b", "c");
Stream<String> streamOfCollection = collection.stream();

Our collection will most likely have an external source at some point,
we’ll probably end up with a method similar to the one below when
creating streams from collections:

public Stream<String> collectionAsStream(Collection<String> collection) {
    return collection.stream();
}

This is can cause some problems. When the provided collection points to
a null reference, the code will throw a NullPointerException at
runtime.

The following section addresses how we can protect against this.

4. Making Created Collection Streams Null-Safe

4.1. Add Checks to Prevent Null Dereferences

To prevent unintended null pointer exceptions, we can opt to add
checks to prevent null references
when creating streams from
collections:

Stream<String> collectionAsStream(Collection<String> collection) {
    return collection == null
      ? Stream.empty()
      : collection.stream();
}

This method, however, has a couple of issues.

First, the null check gets in the way of the business logic decreasing
the overall readability of the program.

Second, the use of null to represent the absence of a value is
considered a wrong approach post-Java SE 8: There is a better way to
model the absence and presence of a value.

It’s important to keep on mind that an empty Collection isn’t the same
as a null Collection. While the first one is indicating that our
query doesn’t have results or elements to show, the second one is
suggesting that a kind of error just happened during the process.

4.2. Use emptyIfNull Method from CollectionUtils Library

We can opt to use Apache Commons’
CollectionUtils
library to make sure our stream is null safe. This library provides an
emptyIfNull method which returns an immutable empty collection given a
null collection as an argument, or the collection itself otherwise:

public Stream<String> collectionAsStream(Collection<String> collection) {
    return emptyIfNull(collection).stream();
}

This is a very simple strategy to adopt. However, it depends on an
external library. If a software development policy restricts the use of
such a library, then this solution is rendered null and void.

4.3. Use Java 8’s Optional

Java SE 8’s Optional is a
single-value container that either contains a value or doesn’t. Where a
value is missing, the Optional container is said to be empty.

Using Optional can be arguably considered as the best overall strategy
to create a null-safe collection from a stream.

Let’s see how we can use it followed by a quick discussion below:

public Stream<String> collectionToStream(Collection<String> collection) {
    return Optional.ofNullable(collection)
      .map(Collection::stream)
      .orElseGet(Stream::empty);
}
  • Optional.ofNullable(collection) creates an Optional object from
    the passed-in collection. An empty Optional object is created if the
    collection is null.

  • map(Collection::stream) extracts the value contained in the
    Optional object as an argument to the map method
    (Collection.stream())

  • orElseGet(Stream::empty) returns the fallback value in the event
    that the Optional object is empty, i.e the passed-in collection is
    null.

As a result, we proactively protect our code against unintended null
pointer exceptions.

4.4. Use Java 9’s Stream OfNullable

Examining our previous ternary example in section 4.1. and considering
the possibility of some elements could be null instead of the
Collection, we have at our disposal the ofNullable method in
the Stream class.

We can transform the above sample to:

Stream<String> collectionAsStream(Collection<String> collection) {
  return collection.stream().flatMap(s -> Stream.ofNullable(s));
}

5. Conclusion

In this article, we briefly revisited how to create a stream from a
given collection. We then proceeded to explore the three key strategies
for making sure the created stream is null-safe when created from a
collection.

Finally, we pointed out the weakness of using each strategy where
relevant.

As usual, the full source code that accompanies the article is available
over
on GitHub
.

Leave a Reply

Your email address will not be published.