为什么Collections.sort不带比较器,而List.sort必须带比较器?

我不明白为什么List.sort()没有没有比较器的版本的逻辑。

我特别看到可以用null调用List.sort:
list.sort(null),并且似乎使用自然顺序进行排序。

我在我的IDE Collections.sort()中注意到List.sort(null),所以我想知道为什么Java 8中最近引入的List.sort没有一个没有比较器的简单版本,在很多情况下是不需要的。

此外,在这种情况下,我不确定是否最好调用List.sort(null)以避免进行额外的调用,还是仍然首选调用Collections.sort()并避免使用丑陋的null参数。

xvjingkuaile 回答:为什么Collections.sort不带比较器,而List.sort必须带比较器?

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

大家都在问