tldr
这是一个设计决策,并结合了一些历史原因。可以添加list.sort()
,但不能保证仅在运行时的安全性。对于JDK而言,这将是一个相当奇怪且不寻常的设计。
Collections#sort
集合可以在方法声明中指定类型边界,因此可以强制使用Comparable
元素:
public static <T extends Comparable<? super T>> void sort(List<T> list)
因此,该方法可以确保集合包含Comparable
个元素。因此不需要Comparator
。
列表#sort
List
无法做到这一点。它的通用类型必须允许所有内容。尽管可能不是List<Dog>
,但您必须能够使用Comparable
。
因此,如果有一个list.sort()
,则此方法将需要确定列表的通用类型T
是否为Comparable
。但是该信息仅在运行时提供,尽管我们希望在编译时提供一个不错的设计。
因为这会导致错误的设计,所以list.sort()
不存在。因此,强制使用Comparator
的额外方法可以确保编译时的安全性。
list.sort(null)
拥有list.sort(null)
而非list.sort()
显然是设计选择,在我看来,这是一个不错的选择。如前所述,List
无法确保编译时的安全性。因此,唯一的选择就是追求运行时的安全性,但效果不佳。
拥有{}有时只能工作并且抛出异常的list.sort()
,否则这将是一个奇怪的设计选择。但是,像list.sort(null)
这样的呼叫对于任何用户来说都更加清晰。特别是,很显然,这将由运行时决策而不是编译时检查覆盖。
您可能希望更明确一些,并赋予其使用自然顺序的普通Comparator
:
list.sort(Comparator.naturalOrder());
至少对于读者来说这更清楚。
历史
您现在可能想知道为什么List.sort(null)
甚至是受支持的功能,以及为什么它们不要求您始终给它一个明确的Comparator
。我无法调查开发人员的想法,但我怀疑历史原因。 JDK中有很多类似的示例,尤其是排序。
这主要是因为Java保持了向后兼容性。 Java 5引入了泛型,因此之前处理容器的所有内容在设计时都没有考虑类型安全性。
有两个高度相关的示例:
-
Arrays#sort(Object[])
(自Java 1.2起)不强制使用Comparable
。因此,他们必须像Arrays.sort(T[],Comparator)
示例一样,在Java 5 List
中增加额外的重载。
- 方法
Collections.sort(T[],Comparator)
实际上接受比较器的null
。一个糟糕的设计选择,但它是在当时还不存在泛型的情况下做出的。因此他们无法再删除此功能。
- 有趣的是,他们决定让
List.sort(Comparator)
(一种新方法)也支持null
。但是,在Stream.sort(Comparator)
中却没有。这是JDK中的一个奇怪的不一致之处。
,
不提供比较器时,将使用natural
排序,仅适用于实现Comparable
的类型。
如果您查看Collections.sort()
的方法定义:
public static <T extends Comparable<? super T>> void sort(List<T> list)
元素类型的范围使得它必须实现Comparable
。
List
不受此限制,因为在很多情况下,您希望列表保存没有自然顺序的东西。因此,您无法调用sort()
,因为List
无法保证它以自然顺序保存元素。
您可以对此进行测试:
以下是编译错误:
List<Object> objs = new ArrayList<>();
objs.add(new Object());
objs.add(new Object());
Collections.sort(objs);
由于Object
未实现Comparable<Object>
,因此除非您提供比较器,否则没有明智的方式对它们进行排序。
如果我绕过Collections
类,只需这样做:
List<Object> objs = new ArrayList<>();
objs.add(new Object());
objs.add(new Object());
objs.sort(null);
我得到一个例外,解释相同:
java.lang.ClassCastException: class java.lang.Object cannot be cast to class java.lang.Comparable
,
我不明白为什么list.sort()没有没有比较器的版本的逻辑?
这也是我不理解的,但是我想这只是介绍该方法的程序员的个人喜好。
由于Java 1.8支持接口中的默认方法,因此很容易添加不带参数List.sort()
的重载版本以明确说明该参数是可选的。该方法可以简单地委托给sort(Comparator)
方法。
我通常会介绍重载方法,以弄清哪些参数是可选的,哪些不是可选的。
我的简单规则是:
- 方法指定了一个参数,因为它需要它。因此,默认情况下它是强制性的。
- 如果可选,则提供不带该参数的重载方法。
此外,我不确定在这种情况下最好调用list.sort(null)以避免额外的调用,或者仍然首选collection.sort()并避免使用难看的null参数。
我不会担心,因为如果您遇到一个额外的电话,那么您真的会遇到麻烦。因此,请选择您认为更易于理解的版本。
JIT编译器也有可能通过内联来删除该调用。
本文链接:https://www.f2er.com/2439485.html