The Set
interface makes no promises on whether implementations permit null
elements. Each implementation is supposed to declare this in its documentation.
Collectors.toSet()
promises to return an implementation of Set
but explicitly makes “no guarantees on the type, mutability, serializability, or thread-safety of the Set
returned”. Null-safety is not mentioned.
The current implementation of Collectors.toSet()
in OpenJDK always uses HashSet
, which permits null elements, but this could change in the future and other implementations may do differently.
If a Set
implementation prohibits null
elements, it throws NullPointerException
at various times, in particular during an attempt to add(null)
. It would seem that if Collectors.toSet()
decided to use a null-intolerant Set
implementation, calling stream.collect(Collectors.toSet())
on a Stream stream
would throw. The specification of collect
does not list any exceptions, nor does the specification of any of the Collector
methods. This could suggest that the collect
call permits nulls within stream
, but on the other hand it’s not clear whether this actually means much at all, as NullPointerException
is an unchecked exception and doesn’t strictly have to be listed.
Is this specified more clearly anywhere else? In particular, is the following code guaranteed not to throw? Is it guaranteed to return true
?
import java.util.stream.*;
class Test {
public static boolean setContainsNull() {
return Stream.of("A", "list", "of", null, "strings")
.collect(Collectors.toSet())
.contains(null);
}
}
If not, then I assume we should always ensure a stream contains no nulls before using Collectors.toSet()
or be ready to handle NullPointerException
. (Is this exception alone enough though?) Alternatively, when this is unacceptable or hard, we can request a specific set implementation using code like Collectors.toCollection(HashSet::new)
.
Edit: there is an existing question that sounds superficially similar, and this question got closed as a supposed duplicate of that. However, the linked question does not address Collectors.toSet()
at all. Moreover, the answers to that question form the underlying assumptions of my question. That question asks: are nulls allowed in streams? Yes. But what happens when a (perfectly allowed) stream that contains nulls gets collected via a standard collector?