
I've been writing Java since before Generics and still ran into this landmine:
Coworker (reviewing my code): container.contains(null)
can throw a NullPointerException.
Me: I don't think so, the docs say:
Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e)).
And this code works as I expect:
import java.util.*;
public class Contains {
public static void main(String[] args) {
// Interestingly, List.of requires all its elements be non-null. Weird.
// var list1 = List.of("foo", "bar", "baz");
// var list2 = List.of("foo", "bar", null);
var list1 = makeCollection("foo", "bar", "baz");
var list2 = makeCollection("foo", "bar", null);
check(list1);
check(list2);
}
private static Collection<String> makeCollection(String... args) {
// return Arrays.asList(args);
return new HashSet<String>(Arrays.asList(args));
}
private static void check (Collection<String> list) {
System.out.println(list.contains(null));
}
}
Coworker: read a bit further. Docs also say:
Throws […] NullPointerException - if the specified element is null and this collection does not permit null elements (optional)
… sure enough. In my case I'm actually using a Set.of(predefined, elements)
, and that particular implementation will throw
if passed a null
.
UGHHh. NULLS.
FWIW, Kotlin handles this much more nicely:
fun main() {
val c1 = setOf("foo", "bar")
val c2 = setOf("foo", null)
val value: String? = null
println(c1.contains(value))
println(c2.contains(value))
}
… though you can only depend on that sane behavior when using its setOf()
constructor. If you might ever be passed a non-null-safe Java Collection you're back to needing to protect yourself against NPEs.