Question ahead:
why does in Java the call coll.contains(null) fail for ImmutableCollections?
I know, that immutable collections cannot contain null-elements, and I do not want to discuss whether that's good or bad.
But when I write a Function, that takes a (general, not explicit immutable) Collection, it fails upon checking for nulls. Why does the implementation not return false (which is actually the 'correct' answer)?
And how can I properly check for nulls in a Collection in general?
Edit:
with some discussions (thanks to the commenters!) I realized, that I mixed up two things: ImmutableCollection from the guava library, and the List returned by java.util.List.of, being some class from ImmutableCollections. However, both classes throw an NPE on .contains(null).
My problem was with the List.of result, but technically the same would happen with guaves implementation. [edit: It does not]
I am distressed by this discussion!
Collections that do this have been a pet peeve of mine since before I wrote the first collections that eventually became Guava. If you find any Guava collection that throws NPE just because you asked it a perfectly innocent question like .contains(null), please file a bug! We hate that crap.
EDIT: I was so distressed that I had to go back to look at my 2007 changelist that first created ImmutableSet and saw literally this:
@Override public boolean contains(@Nullable Object target) {
if (target == null) {
return false;
}
ahhhhh.
The problem gets worse, if calling containsAll() on ImmutableCollections:
@Override
public boolean contains(Object o) {
return o.equals(e0) || e1.equals(o); // implicit nullcheck of o
}
which uses AbstractCollection's super implementation:
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
This provokes a NullPointerException, as soon as the (disallowing null) ImmutableCollection's check against another Collection (that allows null) encounters a null reference.
So, when trying something like this, where an ImmutableCollection is compared against a HashSet (in OpenJDK 15):
Set.of("").containsAll(Stream.of((Object)null).collect(Collectors.toSet()));
A NullPointerException is thrown. Things like that can make it very unpleasant to work with the 'modern' Collection API in projects, that have a way back history.
You'd have to do a potentially absurd explicit check of the compared 'legacy' Collection beforehand like this:
Collection coll = Stream.of((Object)null).collect(Collectors.toSet());
boolean hasNull = coll == null || coll.contains(null);
if (!hasNull) {
Set.of("").containsAll(coll);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With