[英]Why can Collections.sort take no comparator but List.sort must take a comparator?
I don't understand the logic why List.sort() doesn't have a version with no comparator.我不明白为什么 List.sort() 没有没有比较器的版本的逻辑。
Specially I see it's possible to call List.sort with null:特别是我看到可以用 null 调用 List.sort:
list.sort(null)
, and it seems it uses the natural order for sorting. list.sort(null)
,它似乎使用自然顺序进行排序。
I noticed in my IDE Collections.sort() calls List.sort(null), so I was wondering why List.sort which seems to be more recently introduced in Java 8 doesn't have a simple version with no comparator, which in many cases is not needed.我注意到我的 IDE Collections.sort() 调用 List.sort(null),所以我想知道为什么 List.sort 似乎是最近在 ZD52387880E1EA22817A7,2D37592131 中引入的一个简单版本,其中很多没有比较器不需要案例。
Also I am not sure in this situation whether it's better to call List.sort(null) to avoid an extra call, or if it's still preferred to call Collections.sort() and avoid the ugly null argument.另外我不确定在这种情况下是否最好调用 List.sort(null) 以避免额外的调用,或者是否仍然更喜欢调用 Collections.sort() 并避免丑陋的 null 参数。
It is a design decision, mixed with some historical reasons.这是一个设计决定,混合了一些历史原因。 It would be possible to add a
list.sort()
but it could not ensure safety at compile-time, only runtime.可以添加
list.sort()
但它不能确保编译时的安全,只有运行时。 Which would be a rather weird and unusual design for the JDK.对于 JDK 来说,这将是一个相当奇怪和不寻常的设计。
Collections, because it can specify type bounds in the method declaration, has the possibility to force Comparable
elements: Collections,因为它可以在方法声明中指定类型边界,所以有可能强制
Comparable
元素:
public static <T extends Comparable<? super T>> void sort(List<T> list)
So the method can ensure that the collection contains Comparable
elements.因此该方法可以确保集合包含
Comparable
元素。 So a Comparator
is not needed.所以不需要
Comparator
器。
List
can not do that. List
无法做到这一点。 Its generic type must allow everything, You have to be able to use a List<Dog>
although those are maybe not Comparable
.它的泛型类型必须允许一切,您必须能够使用
List<Dog>
尽管那些可能不是Comparable
。
So if there would be a list.sort()
, then this method would need to figure out whether the lists generic type T
is Comparable
or not.因此,如果存在
list.sort()
,那么此方法将需要确定列表泛型类型T
是否为Comparable
。 But that information is only present on runtime, we want it at compile-time for a nice design though.但是这些信息只存在于运行时,我们希望它在编译时得到一个好的设计。
Because this would lead to a bad design, list.sort()
does not exist.因为这会导致糟糕的设计,
list.sort()
不存在。 Hence the extra method forcing a Comparator
which can ensure safety at compile-time..因此,强制使用
Comparator
的额外方法可以确保编译时的安全性。
Having list.sort(null)
instead of list.sort()
is clearly a design choice , a good one in my opinion. list.sort(null)
而不是list.sort()
显然是一种设计选择,在我看来是一个很好的选择。 As said before, it is not possible for List
to ensure safety at compile-time.如前所述,
List
无法在编译时确保安全。 So the only choice is to go for runtime safety, which is not as good.因此,为了运行时安全性,唯一的选择是 go,这不是那么好。
Having a list.sort()
that only sometimes works and throws an exception otherwise would be a weird design choice.有一个
list.sort()
只在某些时候有效并抛出异常,否则将是一个奇怪的设计选择。 A call like list.sort(null)
however is much clearer to any user.然而,像
list.sort(null)
这样的调用对任何用户来说都更加清晰。 Especially, it is clearer that this will be covered by runtime decisions, not by compile-time checks.特别是,更清楚的是,这将被运行时决策覆盖,而不是编译时检查。
You might want to prefer to make it explicit and give it the trivial Comparator
that uses the natural ordering:您可能希望使其显式化并为其提供使用自然排序的普通
Comparator
:
list.sort(Comparator.naturalOrder());
That would at least be even clearer to a reader.这至少对读者来说会更清楚。
You might wonder now why List.sort(null)
even is a supported feature and why they do not require you to give it an explicit Comparator
always.您现在可能想知道为什么
List.sort(null)
甚至是受支持的功能,以及为什么它们不要求您始终为它提供显式Comparator
。 I can not look into the developers mind but I suspect historical reasons.我无法调查开发人员的想法,但我怀疑是历史原因。 There are quite a few similar examples in the JDK, especially with sorting.
JDK 中有很多类似的示例,尤其是排序方面。
This is mainly because Java maintains backwards compatibility.这主要是因为 Java 保持了向后兼容性。 Generics were introduced with Java 5, so everything that existed before which was dealing with containers was not designed with type safety in mind.
Generics 是在 Java 5 中引入的,因此之前存在的处理容器的所有内容在设计时都没有考虑到类型安全。
There are a couple of highly related examples:有几个高度相关的例子:
Arrays#sort(Object[])
(since Java 1.2) does not force Comparable
. Arrays#sort(Object[])
(自 Java 1.2 起)不强制Comparable
。 Therefore, they had to add an extra overload in Java 5 Arrays.sort(T[], Comparator)
, exactly like the List
example.Arrays.sort(T[], Comparator)
中添加额外的重载,就像List
示例一样。Collections.sort(T[], Comparator)
actually accepts null
for the comparator.Collections.sort(T[], Comparator)
实际上接受null
作为比较器。 A bad design choice, but it was made back then when generics did not exist yet.List.sort(Comparator)
, a new method, also support null
.List.sort(Comparator)
也支持null
。 However, in Stream.sort(Comparator)
they did not.Stream.sort(Comparator)
他们没有。 This is a weird inconsistency in the JDK. When you provide no comparator, the natural
ordering is used, which is only applicable for types which implement Comparable
.当您不提供比较器时,将使用
natural
排序,这仅适用于实现Comparable
的类型。
If you look at the method definition for Collections.sort()
:如果您查看
Collections.sort()
的方法定义:
public static <T extends Comparable<? super T>> void sort(List<T> list)
The element type is scoped such that it must implement Comparable
.元素类型的范围是这样的,它必须实现
Comparable
。
A List
does not have that constraint, as there are plenty of cases where you want a list to hold things without a natural order. List
没有这种约束,因为在很多情况下,您希望列表保存没有自然顺序的事物。 As such, you can't call sort()
, because the List
can't guarantee that it's holding elements with a natural ordering.因此,您不能调用
sort()
,因为List
不能保证它包含具有自然顺序的元素。
You can test this:您可以对此进行测试:
The following is a compile error:以下是编译错误:
List<Object> objs = new ArrayList<>();
objs.add(new Object());
objs.add(new Object());
Collections.sort(objs);
because Object
does not implement Comparable<Object>
, there is no sensible way to sort them unless you provide a comparator.因为
Object
没有实现Comparable<Object>
,所以除非您提供比较器,否则没有明智的方法对它们进行排序。
If I bypass the Collections
class and just do this:如果我绕过
Collections
class 并这样做:
List<Object> objs = new ArrayList<>();
objs.add(new Object());
objs.add(new Object());
objs.sort(null);
I get an exception, that explains the same:我得到一个例外,解释相同:
java.lang.ClassCastException: class java.lang.Object cannot be cast to class java.lang.Comparable
I don't understand the logic why list.sort() doesn't have a version with no comparator?
我不明白为什么 list.sort() 没有没有比较器的版本的逻辑?
That's what I also don't understand, but I guess it is just a personal preference of the programmer who introduced that method.这也是我不明白的地方,但我想这只是介绍该方法的程序员的个人喜好。
Since Java 1.8 supports default methods in interfaces it would have been easy to add a overloaded version without a parameter List.sort()
to make clear that the parameter is optional.由于 Java 1.8 支持接口中的默认方法,因此很容易添加不带参数
List.sort()
的重载版本以明确该参数是可选的。 This method could simply delegate to the sort(Comparator)
method.该方法可以简单地委托给
sort(Comparator)
方法。
I usually introduce overloaded methods to make clear which parameters are optional and which are not.我通常会引入重载方法来明确哪些参数是可选的,哪些不是。
My simple rule is:我的简单规则是:
Also I am not sure in this situation it's better to call list.sort(null) to avoid an extra call, or it's still preferred to collection.sort() and avoiding the ugly null argument.
另外我不确定在这种情况下最好调用 list.sort(null) 以避免额外的调用,或者仍然首选 collection.sort() 并避免丑陋的 null 参数。
I wouldn't worry about that, because if that one extra call is your problem than you are really in trouble.我不会担心这一点,因为如果那一个额外的电话是您的问题,那么您就真的有麻烦了。 So choose a version that you think is more understandable.
所以选择一个你认为更容易理解的版本。 It is also possible that the JIT-compiler removes the call by inlining.
JIT 编译器也有可能通过内联删除调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.