为什么不能在构造函数中同时传递集合和比较器? [英] Why can't collections and comparators be passed at once in constructor?

查看:29
本文介绍了为什么不能在构造函数中同时传递集合和比较器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在几个 java API 中观察到了这一点,例如:TreeSet、PriorityQueue 等,没有构造函数同时采用 CollectionComparator.相反,我们必须选择采用 Comparator 的构造函数之一,并使用 addAll 传入 Collection

I have observed this in a couple of java API's that eg: TreeSet, PriorityQueue etc that there is no constructor that takes both Collection and Comparator. Instead we have to pick one of the constructor that takes Comparator and use addAll to pass in the 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 c, Comparatorcomparator) 这样的构造函数?

Is this just an insufficient/inflexible API? Or it is a genuine reason to split them out that I am not aware of? In other words, I am trying to ask why dont we have a constructor like TreeSet(Collection<? extends E> c, Comparator<? super E> comparator)?

推荐答案

TreeSet(Collection) 构造函数的存在是一个额外的便利.在内部,实现 只需调用 Comparator 构造函数,然后调用 addAll().

The fact that a TreeSet(Collection) constructor exists at all is an additional convenience to begin with. Internally, the implementation simply calls the Comparator constructor then addAll().

我想它们只是没有包括更多的便利.没有特别的理由说明为什么这样的构造函数不能存在.

I'd imagine they simply did not include further conveniences. There is no particular reason why such a constructor couldn't exist.

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

However, conceptually, it is a little odd to specify both a source collection and an initial comparator, since constructing a TreeSet by specifying a collection to the constructor, to me at least, indicates that the resulting TreeSet will be a copy of the input set (in that it contains the same elements) - simply by convention.

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

Being able to supply a Comparator in addition to a Collection allows for the possibility that the new TreeSet does not end up containing the same elements if, e.g., the input was another TreeSet but the new Comparator makes some elements identical. To that end, forcing you to call addAll() in such a case also forces you to use code that clearly indicates your intentions.

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

That said, if the natural ordering of the items in the source collection conflict with any comparator that a source set may have used, it still presents the same possibility when TreeSet(Collection) is used.

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

The previous statement isn't quite true. If the source set is the type of set that uses a custom comparator, then it is actually a SortedSet, and the TreeSet(SortedSet) constructor is used instead, which takes on the same comparator as the source set. So unless you go out of your way to construct a non-SortedSet middle-man, the current collection of TreeSet constructors will not let you create a TreeSet that leads to a different set of elements than the source had. In other words: By not providing the Collection+Comparator constructor you are asking about, the designers have also eliminated the possibility of changing the comparator via constructor; thus a newly constructed TreeSet will always have the same elements in it as the source collection, in all cases. This is a compelling reason to not provide that constructor (and also suggests the reason for a separate SortedSet constructor to exist at all).

此外,也许设计师只是选择在他们提供的构造函数处绘制便利线.

Additionally, perhaps the designers simply chose to draw the convenience line at the constructors they provided.

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

As an aside: The bonus effect of the SortedSet constructor is that it eliminates the possibility of a mistake like this:

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

并且让 workingSet 无意中包含了 items 的子集(例如,如果 items 是一个 HashSet 那么workingSet 使用自然排序,这很好,但是如果 items 是带有自定义比较器的 TreeSet,并且使用了 workingSet碰巧与比较器冲突的自然顺序,那么就会有问题).当前的构造函数集强制您清楚地显示意图并明确地采取任何可能改变比较器的操作.

And having workingSet inadvertently end up containing a subset of items (e.g. if items was a HashSet then workingSet uses natural ordering and it's fine, but if items was a TreeSet with a custom comparator, and workingSet used the natural ordering that happened to conflict with the comparator, then there would be a problem). The current set of constructors forces you to clearly display intent and explicitly take any actions that may change the comparator.

这篇关于为什么不能在构造函数中同时传递集合和比较器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆