【问题标题】:Why can't collections and comparators be passed at once in constructor?为什么不能在构造函数中同时传递集合和比较器?
【发布时间】:2014-03-23 21:05:51
【问题描述】:

我在几个 java API 中观察到这一点,例如:TreeSet、PriorityQueue 等,没有构造函数同时采用 CollectionComparator。相反,我们必须选择一个采用 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&lt;? extends E&gt; c, Comparator&lt;? super E&gt; comparator) 这样的构造函数?

【问题讨论】:

  • 第三个选项是TreeSet(SortedSet&lt;E&gt;),它使用与源集相同的排序顺序。
  • 你能澄清你在问什么。你想要一个像 TreeSet(Collection extends E> c, Comparator super E>comparator) 这样的构造函数吗??
  • 你能解释一下为什么你想要这样一个构造函数吗?虽然没有人争辩说拥有一个会很方便,但如果您可以更准确地描述您的具体情况,也许我们可以建议您的代码保持清晰和干净的方法。

标签: java api sorting collections


【解决方案1】:

TreeSet(Collection) 构造函数存在这一事实为开始提供了额外的便利。在内部,the implementation 只需调用Comparator 构造函数,然后调用addAll()

我想他们根本不包括更多的便利。这样的构造函数不能存在并没有什么特别的原因。

但是,从概念上讲,同时指定源集合和初始比较器有点奇怪,因为通过向构造函数指定集合来构造 TreeSet,至少对我而言,表明生成的 TreeSet 将成为输入集的副本(因为它包含相同的元素) - 只是按照惯例。

能够在Collection 之外提供Comparator 允许新的TreeSet 确实最终包含相同的元素,例如,输入是另一个TreeSet 但新的Comparator 使某些元素相同。为此,在这种情况下强迫您致电addAll() 也会迫使您使用清楚表明您的意图的代码。

也就是说,如果源集合中项目的自然顺序与源集可能使用的任何比较器冲突,则在使用TreeSet(Collection) 时仍然存在相同的可能性。

编辑:

前面的说法并不完全正确。如果源集是使用自定义比较器的集类型,那么它实际上是SortedSet,而是使用TreeSet(SortedSet) 构造函数,它采用与源集相同的比较器。因此,除非您不遗余力地构造一个非SortedSet 中间人,否则TreeSet 构造函数的当前集合不会让您创建一个TreeSet,它会导致一组与源不同的元素。换句话说:通过不提供您所询问的Collection+Comparator 构造函数,设计人员还消除了通过构造函数更改比较器的可能性;因此,在所有情况下,新建的TreeSet始终在其中包含与源集合相同的元素。这是不提供该构造函数的一个令人信服的理由(也表明存在单独的 SortedSet 构造函数的原因)。

此外,也许设计者只是选择在他们提供的构造函数处画出便利线。


顺便说一句:SortedSet 构造函数的额外作用是它消除了像这样的错误的可能性:

void doWork (Set<E> items) {
    TreeSet<E> workingSet = new TreeSet<E>(items);
    ...
}

workingSet 无意中最终包含items 的子集(例如,如果itemsHashSet,那么workingSet 使用自然排序,这很好,但如果itemsTreeSet使用自定义比较器,并且workingSet 使用了与比较器发生冲突的自然顺序,那么就会有问题)。当前的构造函数集强制您清楚地显示意图并明确执行任何可能更改比较器的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 2018-01-15
    相关资源
    最近更新 更多