Java 16
Here's an option of generation a Stream from nullable source using Java 16 Stream.mapMulti()
.
This operation expects an argument of type BiConsumer
, i.e. a consumer, which in turn takes two arguments: a stream element and a consumer of the resulting type. Each value offered to the consumer becomes a new stream element, replacing the initial element.
public <T> Stream<T> getStream(Collection<? extends T> c) {
return Stream.ofNullable(c).mapMulti(Iterable::forEach);
}
Where the method reference Iterable::forEach
representing the BiConsumer
is an equivalent of the following lambda expression (explicit types provided for descriptiveness):
(Collection<? extends T> coll, Consumer<T> consumer) -> coll.forEach(consumer)
As well as flatMap()
operation, mapMulti()
is meant to perform one-to-many transformations replacing the consumed original stream element with 0+
(zero or more) elements.
Note that mapMulti()
would perform better than flatMap()
if you need to flatten a significant number of lists which contain only a few elements or can be empty. Here's a quote from the API Note:
This method is preferable to flatMap
in the following circumstances:
- When replacing each stream element with a small (possibly zero) number of elements. Using this method avoids the overhead of creating
a new
Stream
instance for every group of result elements, as required
by flatMap
.
...
Note
1. Lists (as well as other Collections and arrays) are containers of data, i.e. when you need something from a list you're interested the actual values are stored inside. A nullable container of data forces you to be right defensive unrelated to your business-logic and you or colleague might forget about that (which creates a problem which might surface at any moment).
Regardless of the source of nullable Collections, if you have a possibility to change the code you're working with, you can eliminate the actual problem, instead of hiding it using Stream.ofNullable()
or abusing Optional
.
These are possible sources of nullable Collections and treatments for them:
- A nullable Collection comes from a Custom object wrapped around it. Assign the field with an empty Collection by default.
- The data was received, for instance, as a JSON payload, and a property representing the Collection is missing or null. That basically the previous case in disguise. Examine the functionality of your parsing tool, most likely you would find a way to assign default values for properties that are absent a come as null.
- If you have a method returning a nullable Collection, then add a single condition before returning a value instead of having null-checks and null-friendly moves sprinkled all over the code. Refer to the classic book "Effective Java" by Joshua Bloch, Item: "Return empty collections or arrays, not nulls".
2. If you need a quick way to make the code working, but you want to be aware if the incoming list null
, then add the conditional statement to reflect the event in the logs:
if (list != null) logger.log( ... );
3. Lastly, as @Stuart Marks has pointed out in his answer to this question Optional
wasn't designed for performing/hiding null-checks. And here's a few more references regarding this topic: