我在几个java API中观察到这一点,例如:TreeSet,PriorityQueue等,没有构造函数同时使用Collection
和Comparator
。相反,我们必须选择一个带Comparator
的构造函数并使用addAll传递Collection
例如:
TreeSet(Collection<? extends E> c)
Constructs a new tree set containing the elements in the specified collection, sorted according to the natural ordering of its elements.
TreeSet(Comparator<? super E> comparator)
Constructs a new, empty tree set, sorted according to the specified comparator.
这只是一个不够/不灵活的API吗?或者将它们拆分出来是我不知道的真正原因?
换句话说,我想问为什么我们没有像TreeSet(Collection<? extends E> c, Comparator<? super E> comparator)
这样的构造函数?
答案 0 :(得分:2)
一个TreeSet(Collection)
构造函数存在的事实是一个额外的便利开始。在内部,the implementation只需调用Comparator
构造函数,然后调用addAll()
。
我想他们根本就没有包含更多便利。没有特别的理由为什么这样的构造函数不能存在。
然而,从概念上讲,同时指定源集合和初始比较器有点奇怪,因为通过为构造函数指定集合来构造TreeSet
,至少对我来说,表明结果为{{ 1}}将是输入集的副本(因为它包含相同的元素) - 只需按惯例。
除了TreeSet
之外,能够提供Comparator
可以让新的Collection
TreeSet
,但新TreeSet
使一些元素相同。为此,在这种情况下强迫您拨打Comparator
也会强制您使用明确表明您意图的代码。
也就是说,如果源集合中项目的自然顺序与源集合可能使用的任何比较器冲突,则在使用addAll()
时它仍然具有相同的可能性。 击>
编辑:
之前的陈述并不完全正确。如果源集是使用自定义比较器的集合的类型,那么它实际上是TreeSet(Collection)
,而使用TreeSet(SortedSet)
构造函数,它与源集合使用相同的比较器。因此,除非你不遗余力地构建一个非SortedSet
中间人,否则当前SortedSet
构造函数的集合将不允许你创建导致另一组TreeSet
的{{1}}元素比源有。换句话说:通过不提供您所询问的TreeSet
+ Collection
构造函数,设计人员也消除了通过构造函数更改比较器的可能性;因此,在所有情况下,新构造的Comparator
将总是在其中具有与源集合相同的元素。这是一个令人信服的理由,不提供该构造函数(并且还建议单独存在单独的TreeSet
构造函数的原因)。
此外,也许设计师只是选择在他们提供的构造函数中绘制便利线。
顺便说一下:SortedSet
构造函数的奖励效果是它消除了这样的错误的可能性:
SortedSet
让void doWork (Set<E> items) {
TreeSet<E> workingSet = new TreeSet<E>(items);
...
}
无意中最终包含workingSet
的子集(例如,如果items
是items
,则HashSet
使用自然排序,这很好,但如果workingSet
是带有自定义比较器的items
,并且TreeSet
使用了与比较器发生冲突的自然顺序,则会出现问题)。当前的构造函数集强制您清楚地显示意图并明确地采取可能会改变比较器的任何操作。