EnumSet.spliterator 没有特征 Spliterator.NONNULL

EnumSet.spliterator without characteristic Spliterator.NONNULL

我在想问题的答案:

我的第一个想法是检查地图键集的 Spliterator 是否具有特征 Spliterator.NONNULL:

map.keySet().spliterator().hasCharacteristics(Spliterator.NONNULL)

JavaDoc 说:

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.)

在回答之前我做了一些检查:

没有提供CompararatorTreeMapSpliterator没有这个特性,即使自然排序不允许null -键。

new TreeMap<>().keySet().spliterator().hasCharacteristics(Spliterator.NONNULL); // false 

更令人惊讶的是 EnumMap 键集的 SpliteratorEnumSet 本身不具有此特性。

EnumSet.allOf(DayOfWeek.class).spliterator().hasCharacteristics(Spliterator.NONNULL); // false

我理解 spliterator().hasCharacteristics(Spliterator.NONNULL) 在上述情况下的结果 returns false 作为 Set.spliterator() 的默认实现被评估。

但是这些集合的拆分器没有覆盖 Set.spliterator() 来创建 SpliteratorSpliterator.NONNULL 的原因吗?这会破坏我不知道的规范吗?

更糟糕的是:

System.out.println(Set.of(1)
             .spliterator()
             .hasCharacteristics(Spliterator.NONNULL)); // false

即使这些 Set::of 方法记录为:

throws NullPointerException if the element is null

因此无法在 Set 中以 null 结尾。我想真正的答案是尚未完成

编辑

But is there a reason why the spliterators of these sets do not override Set.spliterator() to create a Spliterator with Spliterator.NONNULL?

我们只能推测,但可以肯定的是,某些使用 Comparator 进行排序的 TreeMap 实例确实容纳了空键,因此它们的键集的拆分器一定没有特征Spliterator.NONNULL。虽然使用其键的自然顺序的 TreeMap 确实不能容纳空键,但我个人并不认为 TreeMap 的键集不使用它来进行区分感到惊讶。我希望这种 属性 完全由所涉及的 类 驱动,而不是由每个实例的详细信息驱动。

Would this break a specification I am not aware of?

也许吧。 The docs for Set.spliterator() 指定

The Spliterator reports Spliterator.DISTINCT. Implementations should document the reporting of additional characteristic values.

(强调已添加。)The docs for TreeMap.keySet()

The set's spliterator is late-binding, fail-fast, and additionally reports Spliterator.SORTED and Spliterator.ORDERED with an encounter order that is ascending key order. The spliterator's comparator (see Spliterator.getComparator()) is null if the tree map's comparator (see SortedMap.comparator()) is null. Otherwise, the spliterator's comparator is the same as or imposes the same total ordering as the tree map's comparator.

请注意,此集合的文档符合 Set.spliterator() 文档中的期望集,没有指定,甚至有条件地指定 Spliterator.NONNULL 是键集的拆分器将报告的特征之一。进一步注意,那些相同的文档 do 描述了这些集合的其他特征,这些特征根据地图的顺序是否基于比较器而有所不同。

因此,不,您不应该期望 TreeMap 键集',拆分器在任何情况下都有报告 Spliterator.NONNULL。我无法明确说明做出此选择的原因,但它符合我对 Java 设计理念的看法。

你也写了,

Even more suprising was the fact that Spliterators of an EnumMap keyset and of EnumSet itself do not have this characteristic.

我同意这些分裂者可以合理地报告 Spliterator.NONNULL。我不知道为什么他们选择不这样做,除非这只是一个疏忽。尽管如此,我观察到他们的文档确实没有指定这些拆分器将报告 Spliterator.NONNULL。在这种情况下,可以预料那些拆分器不会报告该特性。