I was thinking about an answer to the question: How to test for null keys on any Java map implementation?
My first thought was to check if the Spliterator
of the keyset of a map has the characteristic Spliterator.NONNULL
:
map.keySet().spliterator().hasCharacteristics(Spliterator.NONNULL)
The JavaDoc says:
Characteristic value signifying that the source guarantees that encountered elements will not be null. (This applies, for example, to most concurrent collections, queues, and maps.)
Before answering I did some checks:
The Spliterator
of aTreeMap
without a provided Compararator
does not have this characteristic even though the natural ordering does not allow null-keys.
new TreeMap<>().keySet().spliterator().hasCharacteristics(Spliterator.NONNULL); // false
Even more suprising was the fact that Spliterator
s of an EnumMap
keyset and of EnumSet
itself do not have this characteristic.
EnumSet.allOf(DayOfWeek.class).spliterator().hasCharacteristics(Spliterator.NONNULL); // false
I understand that the result of spliterator().hasCharacteristics(Spliterator.NONNULL)
in the above cases returns false
as the default implementation of Set.spliterator()
is evaluated.
But is there a reason why the spliterators of these sets do not override Set.spliterator()
to create a Spliterator
with Spliterator.NONNULL
? Would this break a specification I am not aware of?
Even worse:
System.out.println(Set.of(1)
.spliterator()
.hasCharacteristics(Spliterator.NONNULL)); // false
Even if those Set::of
methods are documented as:
throws NullPointerException if the element is null
So there is no way to end up with a null in that Set
. I guess the real answer is that this is not yet done.
EDIT
See the comment from Stuart Marks about this
But is there a reason why the spliterators of these sets do not override
Set.spliterator()
to create aSpliterator
withSpliterator.NONNULL
?
We can only speculate, but certainly it is the case that some TreeMap
instances that use Comparator
s for ordering do accommodate null keys, and therefore their key sets' spliterators must not have characteristic Spliterator.NONNULL
. Although it is true that a TreeMap
that uses its keys' natural ordering cannot accommodate null keys, I do not personally find it surprising that TreeMap
's key sets do not use that to make a distinction. This is the kind of property that I would expect to be driven exclusively by the classes involved, not by per-instance details.
Would this break a specification I am not aware of?
Perhaps. The docs for Set.spliterator()
specify
The
Spliterator
reportsSpliterator.DISTINCT
. Implementations should document the reporting of additional characteristic values.
(Emphasis added.) The docs for TreeMap.keySet() say
The set's spliterator is late-binding, fail-fast, and additionally reports
Spliterator.SORTED
andSpliterator.ORDERED
with an encounter order that is ascending key order. The spliterator's comparator (seeSpliterator.getComparator()
) isnull
if the tree map's comparator (seeSortedMap.comparator()
) isnull
. Otherwise, the spliterator's comparator is the same as or imposes the same total ordering as the tree map's comparator.
Note well that the docs for this set comply with the expectation set in the Set.spliterator()
docs without designating, even conditionally, that Spliterator.NONNULL
is among the characteristics that key sets' spliterators will report. Note further that those same docs do describe other characteristics of those sets that vary depending on whether the map's order is based on a comparator.
Thus, no, you should not expect TreeMap
key sets', spliterators to have report Spliterator.NONNULL
under any circumstances. I cannot definitively speak to why this choice was made, but it is consistent with my perception of Java design philosophy.
You also wrote,
Even more suprising was the fact that
Spliterator
s of anEnumMap
keyset and ofEnumSet
itself do not have this characteristic.
I agree that these spliterators could reasonably report Spliterator.NONNULL
. I do not know why the choice was made that they would not do so, unless it was simply an oversight. Nevertheless, I observe that their docs indeed do not specify that these spliterators will report Spliterator.NONNULL
. With that being the case, it is to be expected that those spliterators will not report that characteristic.
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